1. Libraries and functions

1.1 Libraries

Load the required libraries.

library(tidyverse)
library(sf)
library(here)
library(readxl)
library(scales)
library(DT)
library(brms)
library(tidybayes)
library(patchwork)
library(marginaleffects)
library(ggrepel)
library(scico)
library(ggdensity)
library(ggpubr)
library(units)
#library(ggsn)

1.2 Helper functions

Functions that we will use throughout the script

#labeller for years
year_labels <- c(1950:1963)

#The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
#Segment for graphs to match ACF period
acf_start <- decimal_date(ymd("1957-03-11"))
acf_end <- decimal_date(ymd("1957-04-12"))

Function for counterfactual plots



plot_counterfactual <- function(model_data, model, population_denominator, outcome, grouping_var=NULL, re_formula,...){
  
  #labeller for years
  year_labels <- c(1950:1963)

  #The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
  #Segment for graphs to match ACF period
  acf_start <- decimal_date(ymd("1957-03-11"))
  acf_end <- decimal_date(ymd("1957-04-12"))

  summary <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{outcome}}, {{grouping_var}}) %>%
    add_epred_draws({{model}}, re_formula={{re_formula}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
          .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
          .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                  acf_period=="c. post-acf" ~ "Post Intervention"))



  #create the counterfactual (no intervention), and summarise
  
  counterfact <-
    add_epred_draws(object = {{model}},
                    newdata = {{model_data}} %>%
                                  select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, {{outcome}}) %>%
                                  mutate(acf_period = "a. pre-acf"), re_formula={{re_formula}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
         .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
         .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))
  


  #plot the intervention effect
p <- summary %>%
    droplevels() %>%
    ggplot() +
    geom_ribbon(aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
    geom_ribbon(data = counterfact %>% filter(year>=1956), 
                aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
    geom_line(data = counterfact %>% filter(year>=1956), 
              aes(y=.epred_inc, x=year2, colour="Counterfactual")) +
    geom_line(aes(y=.epred_inc, x=year2, group=acf_period,  colour=acf_period)) +
    geom_point(data = {{model_data}}, aes(y={{outcome}}, x=year2, shape=acf_period), size=2) +
    geom_vline(aes(xintercept=acf_end), linetype=3) +
    theme_ggdist() +
    scale_y_continuous(labels=comma, limits = c(0,NA)) +
    scale_x_continuous(labels = year_labels,
                       breaks = year_labels) +
    scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="", na.translate = F) +
    scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="", na.translate = F) +
    scale_shape_discrete(name="", na.translate = F) +
    labs(
      x = "Year",
      y = "Case notification rate (per 100,000)",
      caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
    ) +
    theme(legend.position = "bottom",
          panel.border = element_rect(colour = "grey78", fill=NA),
          text = element_text(size=8),
          axis.text.x = element_text(size=8, angle = 90, hjust=1, vjust=0.5),
          legend.text = element_text(size=8)) +
    guides(shape="none")

    facet_vars <- vars(...)

  if (length(facet_vars) != 0) {
    p <- p + facet_wrap(facet_vars)
  }
  p

}

Function for calculating measures of change over time (RR.peak, RR.level, RR.slope)


summarise_change <- function(model_data, model, population_denominator, grouping_var = NULL, re_formula = NULL) {
  
  #functions for calculating RR.peak
  #i.e. relative case notification rate in 1957 vs. counterfactual trend for 1957
  
  grouping_var <- enquo(grouping_var)
  
  if (!is.null({{grouping_var}})) {
    
    #make the prediction matrix, conditional on whether we want random effects included or not.
    out <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num == 8),
                    acf_period = c("a. pre-acf", "b. acf")
    )
  } else {
    
    out <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num == 8),
                    acf_period = c("a. pre-acf", "b. acf")
    )
  }
  
  peak_draws <- add_epred_draws(newdata = out,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
    mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
    group_by(.draw, !!grouping_var) %>%
    summarise(estimate = last(epred_cnr)/first(epred_cnr)) %>%
    ungroup() %>%
    mutate(measure = "RR.peak")
  
  peak_summary <- peak_draws %>%
    group_by(!!grouping_var) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.peak")
  
  
  #functions for calculating RR.level
  #i.e. relative case notification rate in 1958 vs. counterfactual trend for 1958
  
    if (!is.null({{grouping_var}})) {
    out2 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num == 9),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  } else {
    
    out2 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num == 9),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  }
  
    level_draws <- add_epred_draws(newdata = out2,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
    arrange(y_num, .draw) %>%
    mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
    group_by(.draw, !!grouping_var) %>%
    summarise(estimate = last(epred_cnr)/first(epred_cnr)) %>%
    ungroup() %>%
    mutate(measure = "RR.level")
  
  level_summary <- level_draws %>%
    group_by(!!grouping_var) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.level")
    
    
  #functions for calculating RR.slope
  #i.e. relative change in case notification rate in 1958-1963 vs. counterfactual trend for 1959-1963
  
    if (!is.null({{grouping_var}})) {
    out3 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  } else {
    
    out3 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  }
  
    slope_draws <- add_epred_draws(newdata = out3,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
        arrange(y_num) %>%
        ungroup() %>%
        mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
        group_by(.draw, y_num, !!grouping_var) %>%
        summarise(slope = last(epred_cnr)/first(epred_cnr)) %>%
        ungroup() %>%
        group_by(.draw, !!grouping_var) %>%
        summarise(estimate = last(slope)/first(slope)) %>%
        mutate(measure = "RR.slope")
  
  slope_summary <- slope_draws %>%
     group_by(!!grouping_var) %>%
      mean_qi(estimate) %>%
      mutate(measure = "RR.slope")
    
  #gather all the results into a named list
    lst(peak_draws=peak_draws, peak_summary=peak_summary, 
        level_draws=level_draws, level_summary=level_summary, 
        slope_draws=slope_draws, slope_summary=slope_summary)
  
}

Function for calculating difference from counterfactual


calculate_counterfactual <- function(model_data, model, population_denominator, grouping_var=NULL, re_formula=NA){
  
  #effect vs. counterfactual
  counterfact <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf"),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc_counterf = .epred/{{population_denominator}}*100000, .epred_counterf=.epred)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, .draw, .epred_counterf, .epred_inc_counterf, {{grouping_var}})
  
  #Calcuate case notification rate per draw, then summarise.
  post_change <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc = .epred/{{population_denominator}}*100000)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, {{grouping_var}}, .draw, .epred, .epred_inc, {{grouping_var}}) 
  
  #for the overall period
    counterfact_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf"),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, .draw, .epred, {{grouping_var}})  %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred_counterf = sum(.epred)) 
  
  #Calcuate case notification rate per draw, then summarise.
  post_change_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, {{grouping_var}}, .draw, .epred) %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred = sum(.epred)) 
  
  
counter_post <-
  left_join(counterfact, post_change) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf,
           diff_inc100k = .epred_inc - .epred_inc_counterf,
           rr_inc100k = .epred_inc/.epred_inc_counterf) %>%
    group_by(year, {{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change, diff_inc100k, rr_inc100k) %>%
    ungroup()

counter_post_overall <-
  left_join(counterfact_overall, post_change_overall) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by({{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup()

lst(counter_post, counter_post_overall)

}

Function for tidying up counterfactuals (mostly for making nice tables)


tidy_counterfactuals <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"),
            diff_inc = glue::glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr_inc = glue::glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"))
}


tidy_counterfactuals_overall <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"))
}

2. Data

Import datasets for analysis

2.1 Shapefiles

Make a map of Glasgow wards


glasgow_wards_1951 <- st_read(here("mapping/glasgow_wards_1951.geojson"))
Reading layer `glasgow_wards_1951' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/glasgow_wards_1951.geojson' using driver `GeoJSON'
Simple feature collection with 37 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -4.393502 ymin: 55.77464 xmax: -4.070411 ymax: 55.92814
Geodetic CRS:  WGS 84

#read in Scotland boundary
scotland <- st_read(here("mapping/Scotland_boundary/Scotland boundary.shp"))
Reading layer `Scotland boundary' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/Scotland_boundary/Scotland boundary.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5513 ymin: 530249 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
#make a bounding box for Glasgow
bbox <- st_bbox(glasgow_wards_1951) |> st_as_sfc()

#plot scotland with a bounding box around the City of Glasgow
scotland_with_bbox <- ggplot() +
  geom_sf(data = scotland, fill="antiquewhite") +
  geom_sf(data = bbox, colour = "#C60C30", fill="antiquewhite") +
  theme_void() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "#EAF7FA", size = 0.3))
Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.
#plot the wards
#note we tidy up some names to fit on map
glasgow_ward_map <- glasgow_wards_1951 %>%
  mutate(ward = case_when(ward=="Shettleston and Tollcross" ~ "Shettleston and\nTollcross",
                          ward=="Partick (West)" ~ "Partick\n(West)",
                          ward=="Partick (East)" ~ "Partick\n(East)",
                          ward=="North Kelvin" ~ "North\nKelvin",
                          ward=="Kinning Park" ~ "Kinning\nPark",
                          TRUE ~ ward)) %>%
  
  ggplot() +
  geom_sf(aes(fill=division)) +
  geom_sf_label(aes(label = ward), size=3, fill=NA, label.size = NA, colour="black") +
  #scale_colour_identity() +
  scale_fill_brewer(palette = "Set3", name="City of Glasgow Division") +
  theme_grey() +
  labs(x="",
       y="",
       fill="Division") +
  theme(legend.position = "top",
        
        panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "antiquewhite", size = 0.3),
        panel.grid.major = element_line(color = "grey78")) +
  guides(fill=guide_legend(title.position = "top", title.hjust = 0.5, title.theme = element_text(face="bold")))

#add the map of scotland as an inset
glasgow_ward_map + inset_element(scotland_with_bbox, 0.75, 0, 1, 0.4)

ggsave(here("figures/s1.png"), height=10, width = 12)

NA
NA

Calculate areas per geographical unit

sf_use_s2(FALSE) #https://github.com/r-spatial/sf/issues/1762
Spherical geometry (s2) switched off
glasgow_wards_1951 <- glasgow_wards_1951 %>%
  mutate(area = st_area(glasgow_wards_1951))


glasgow_wards_1951$area_km <- units::set_units(glasgow_wards_1951$area, km^2)

Make division shape files, and calculate area (stopped working, need to fix!)


# glasgow_divisions_1951 <- glasgow_wards_1951 %>%
#   group_by(division) %>% 
#   summarize(geometry = st_union(geometry)) %>%
#   nngeo::st_remove_holes() %>%
#   mutate(area = st_area(glasgow_divisions_1951))
# 
# glasgow_divisions_1951$area_km <- units::set_units(glasgow_divisions_1951$area, km^2)

3. Denominators

Load in the datasets for denonomiators, and check for consistency.


overall_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "overall_population")

overall_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
overall_pops <- overall_pops %>%
  mutate(year2 = year+0.5)

Note, we have three population estimates:

  1. Population without institutionalised people or people in shipping
  2. Population in institutions
  3. Population in shipping

(Population in shipping is estimated from the 1951 census, so is the same for most years)

3.1 Overall population

First, plot the total population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2), alpha=0.5, colour = "mediumseagreen", fill="mediumseagreen") +
  geom_point(aes(y=total_population, x=year2), colour = "mediumseagreen") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: total population",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

Now the population excluding institutionalised and shipping population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=population_without_inst_ship, x=year2), alpha=0.5, colour = "purple", fill="purple") +
  geom_point(aes(y=population_without_inst_ship, x=year2), colour = "purple") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: population excluding institutionalised and shipping",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

3.2 Population by Ward

There are 5 Divisions containing 37 Wards in the Glasgow Corporation, with consistent boundaries over time.

#look-up table for divisions and wards
ward_lookup <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "divisions_wards")


ward_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "ward_population")

ward_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
ward_pops <- ward_pops %>%
  mutate(year2 = year+0.5)

#Get the Division population
division_pops <- ward_pops %>%
  group_by(division, year) %>%
  summarise(population_without_inst_ship = sum(population_without_inst_ship, na.rm = TRUE),
            institutions = sum(institutions, na.rm = TRUE),
            shipping = sum(shipping, na.rm = TRUE),
            total_population = sum(total_population, na.rm = TRUE))
`summarise()` has grouped output by 'division'. You can override using the `.groups` argument.
division_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Plot the overall population by Division and Ward


division_pops %>%
  mutate(year2 = year+0.5) %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(division~.) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name = "") +
  scale_colour_brewer(palette = "Set3", name = "") +
  labs(
    title = "Glasgow Corporation: total population by Division",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

Approximately, how many person-years of follow-up do we have?


overall_pops %>%
  ungroup() %>%
  summarise(across(year, length, .names = "years"),
            across(c(population_without_inst_ship, total_population), sum)) %>%
  mutate(across(where(is.double), comma)) %>%
  datatable()
NA
NA

Change in population by ward


ward_pops %>%
  group_by(ward) %>%
  summarise(pct_change_pop = (last(population_without_inst_ship) - first(population_without_inst_ship))/first(population_without_inst_ship)) %>%
  mutate(pct_change_pop = percent(pct_change_pop)) %>%
  arrange(pct_change_pop) %>%
  datatable()
NA
NA
NA

Output population density by ward and divison for regression modelling

Wards first

(stopped working, need to fix)


# ward_covariates <-  glasgow_wards_1951 %>%
#   left_join(ward_pops) %>%
#   mutate(people_per_km_sq = as.double(population_without_inst_ship/area_km))
# 
# #plot it out
# 
# ward_covariates %>%
#   ggplot() +
#   geom_sf(aes(fill=people_per_km_sq)) + 
#   facet_wrap(year~., ncol=7) +
#   scale_fill_viridis_c(option="A") +
#   theme(legend.position = "bottom",
#         axis.text.x = element_text(angle = 45, hjust=1))
# 
# ggsave(here("figures/ward_pop_density.png"), width=10)
# 
# write_rds(ward_covariates, here("populations/ward_covariates.rds"))

Now divisions first

(stopped working, need to fix)


# division_covariates <-  glasgow_divisions_1951 %>%
#   left_join(division_pops) %>%
#   mutate(people_per_km_sq = as.double(total_population/area_km))
# 
# #plot it out
# 
# division_covariates %>%
#   ggplot() +
#   geom_sf(aes(fill=people_per_km_sq)) + 
#   geom_sf_label(aes(label = division), size=3, fill=NA, label.size = NA, colour="black", family = "Segoe UI") +
#   facet_wrap(year~., ncol=7) +
#   scale_fill_viridis_c(option="G") +
#   theme(legend.position = "bottom",
#         axis.text.x = element_text(angle = 45, hjust=1))
# 
# ggsave(here("figures/division_pop_density.png"), width=10)
# 
# write_rds(division_covariates, here("populations/division_covariates.rds"))

3.3 Population by age and sex


age_sex <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "age_sex_population") %>%
  pivot_longer(cols = c(male, female),
               names_to = "sex")

#collapse down to smaller age groups to be manageable
age_sex <- age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age == "0 to 4" ~ "00 to 04",
                         age == "5 to 9" ~ "05 to 14",
                         age == "10 to 14" ~ "05 to 14",
                         age == "15 to 19" ~ "15 to 24",
                         age == "20 to 24" ~ "15 to 24",
                         age == "25 to 29" ~ "25 to 34",
                         age == "30 to 34" ~ "25 to 34",
                         age == "35 to 39" ~ "35 to 44",
                         age == "40 to 44" ~ "35 to 44",
                         age == "45 to 49" ~ "45 to 59",
                         age == "50 to 54" ~ "45 to 59",
                         age == "55 to 59" ~ "45 to 59",
                         TRUE ~ "60 & up")) %>%
  group_by(year, age, sex) %>%
  mutate(value = sum(value)) %>%
  ungroup()



m_age_sex <- lm(value ~ splines::ns(year, knots = 3)*age*sex, data = age_sex)

summary(m_age_sex)
Warning: essentially perfect fit: summary may be unreliable

Call:
lm(formula = value ~ splines::ns(year, knots = 3) * age * sex, 
    data = age_sex)

Residuals:
       Min         1Q     Median         3Q        Max 
-1.185e-10  0.000e+00  0.000e+00  0.000e+00  1.185e-10 

Coefficients: (14 not defined because of singularities)
                                                    Estimate Std. Error    t value Pr(>|t|)    
(Intercept)                                        5.222e+04  2.040e-10  2.559e+14   <2e-16 ***
splines::ns(year, knots = 3)1                     -8.043e+03  4.071e-10 -1.976e+13   <2e-16 ***
splines::ns(year, knots = 3)2                             NA         NA         NA       NA    
age05 to 14                                        3.669e+04  2.499e-10  1.468e+14   <2e-16 ***
age15 to 24                                       -3.893e+03  2.499e-10 -1.558e+13   <2e-16 ***
age25 to 34                                       -3.996e+04  2.499e-10 -1.599e+14   <2e-16 ***
age35 to 44                                       -4.230e+04  2.499e-10 -1.693e+14   <2e-16 ***
age45 to 59                                        5.459e+04  2.356e-10  2.317e+14   <2e-16 ***
age60 & up                                         7.533e+04  2.204e-10  3.418e+14   <2e-16 ***
sexmale                                            3.374e+03  2.886e-10  1.169e+13   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14         -1.863e+03  4.985e-10 -3.737e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24          7.533e+04  4.985e-10  1.511e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34          1.325e+05  4.985e-10  2.658e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44          1.380e+05  4.985e-10  2.769e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59          3.474e+03  4.700e-10  7.390e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up          -8.453e+04  4.397e-10 -1.923e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up                  NA         NA         NA       NA    
splines::ns(year, knots = 3)1:sexmale             -1.994e+03  5.757e-10 -3.464e+12   <2e-16 ***
splines::ns(year, knots = 3)2:sexmale                     NA         NA         NA       NA    
age05 to 14:sexmale                                1.053e+04  3.534e-10  2.980e+13   <2e-16 ***
age15 to 24:sexmale                                2.352e+04  3.534e-10  6.656e+13   <2e-16 ***
age25 to 34:sexmale                                1.355e+04  3.534e-10  3.833e+13   <2e-16 ***
age35 to 44:sexmale                               -1.727e+03  3.534e-10 -4.888e+12   <2e-16 ***
age45 to 59:sexmale                                2.774e+03  3.332e-10  8.324e+12   <2e-16 ***
age60 & up:sexmale                                -7.761e+04  3.117e-10 -2.490e+14   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14:sexmale -2.049e+04  7.051e-10 -2.906e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24:sexmale -6.780e+04  7.051e-10 -9.616e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34:sexmale -3.804e+04  7.051e-10 -5.396e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44:sexmale -1.171e+04  7.051e-10 -1.661e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59:sexmale -3.473e+04  6.647e-10 -5.224e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up:sexmale   1.056e+05  6.218e-10  1.698e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up:sexmale          NA         NA         NA       NA    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.074e-11 on 44 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 6.006e+29 on 27 and 44 DF,  p-value: < 2.2e-16
age_levels <- age_sex %>% select(age) %>% distinct() %>% pull() 

age_sex_nd <- 
  crossing(
    age=age_levels,
    sex=c("male", "female"),
    year = 1950:1963
  )

pred_pops <- age_sex_nd %>% modelr::add_predictions(m_age_sex)
Warning: prediction from a rank-deficient fit may be misleading
pred_pops %>%
  ggplot(aes(x=year, y=pred, colour=age)) +
  geom_line() +
  geom_point() +
  facet_grid(sex~.) +
  scale_y_continuous(labels = comma, limits = c(0, 125000))


#How well do they match up with our overall populations?
pred_pops %>%
  group_by(year) %>%
  summarise(sum_pred_pop = sum(pred)) %>%
  right_join(overall_pops) %>%
  select(year, sum_pred_pop, population_without_inst_ship, total_population) %>%
  pivot_longer(cols = c(sum_pred_pop, population_without_inst_ship, total_population)) %>%
  ggplot(aes(x=year, y=value, colour=name)) +
  geom_point() +
  scale_y_continuous(labels = comma, limits = c(800000, 1250000))
Joining with `by = join_by(year)`

pred_pops %>%
  group_by(year, sex) %>%
  summarise(sum = sum(pred)) %>%
  group_by(year) %>%
  mutate(sex_ratio = first(sum)/last(sum))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.

What percentage of adults (15+ participated in the intervention in 1957)?


pred_pops %>%
  ungroup() %>%
  filter(year==1957) %>%
  filter(age != "00 to 04",
         age != "05 to 14") %>%
  summarise(total_pop = sum(pred)) %>%
  mutate(cxr_screened = 622349) %>%
  mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))

pred_pops %>%
  ungroup() %>%
  filter(year==1957) %>%
  filter(age != "00 to 04",
         age != "05 to 14") %>%
  summarise(total_pop = sum(pred), .by=sex) %>%
  mutate(cxr_screened = c(340474, 281875)) %>%
  mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))
NA
NA

Population pyramids

ggsave(here("figures/s3.png"), width=10)
Saving 10 x 7 in image

Not perfect, but resonably good. But ahhhhh… the age groups don’t align with the case notification age groups! Come back to think about this later.

4. Tuberculosis cases

Import the tuberculosis cases dataset

4.1 Overall notifications

Overall, by year.


cases_by_year <- read_xlsx("2023-11-28_glasgow-acf.xlsx", sheet = "by_year")

cases_by_year%>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


#shift year to midpoint
cases_by_year <- cases_by_year %>%
  mutate(year2 = year+0.5)

Plot the overall number of case notified per year, by pulmonary and extra pulmonary classification.


cases_by_year %>%
  select(-total_notifications, -year) %>%
  pivot_longer(cols = c(pulmonary_notifications, `non-pulmonary_notifications`)) %>%
  mutate(name = case_when(name == "pulmonary_notifications" ~ "Pulmonary TB",
                          name == "non-pulmonary_notifications" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

4.2 Notifications by Division

Read in the datasets and merge together.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
ward_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_ward", value)) %>%
  pull(value)


cases_by_ward_sex_year <- map_df(ward_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_ward_sex_year %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Aggregate together to get cases by division


cases_by_division <- cases_by_ward_sex_year %>%
  left_join(ward_lookup) %>%
  group_by(division, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE))
Joining with `by = join_by(ward)``summarise()` has grouped output by 'division', 'year'. You can override using the `.groups` argument.
#shift year to midpoint
cases_by_division <- cases_by_division %>%
  mutate(year2 = year+0.5) %>%
  ungroup()

cases_by_division  %>%
  select(-year2) %>%
  select(year, everything()) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


cases_by_division %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

4.3 Notifications by ward



cases_by_ward <- cases_by_ward_sex_year %>%
  group_by(ward, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE)) %>%
  ungroup()
`summarise()` has grouped output by 'ward', 'year'. You can override using the `.groups` argument.
cases_by_ward %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  select(year, everything()) %>%
  datatable()

#shift year to midpoint
cases_by_ward <- cases_by_ward %>%
  mutate(year2 = year+0.5)

cases_by_ward %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.8) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA

4.4 Notifications by age and sex

As we don’t have denominators, we will just model the change in counts.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
age_sex_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_age_sex", value)) %>%
  pull(value)


cases_by_age_sex <- map_df(age_sex_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_age_sex %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA

5 TB case notification rates

5.1 Overall TB case notification rates

Now calculate case notification rates per 100,000 population

Merge the notification and population denominator datasets together.

Here we need to include the whole population (with shipping and institutions) as they are included in the notifications.


overall_inc <- overall_pops %>%
  left_join(cases_by_year)
Joining with `by = join_by(year, year2)`
overall_inc <- overall_inc %>%
  mutate(inc_pulm_100k = pulmonary_notifications/total_population*100000,
         inc_ep_100k = `non-pulmonary_notifications`/total_population*100000,
         inc_100k = total_notifications/total_population*100000)

overall_inc %>%
  select(year, inc_100k, inc_pulm_100k, inc_ep_100k) %>%
  mutate_at(.vars = vars(inc_100k, inc_pulm_100k, inc_ep_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

overall_inc %>%
  select(year2, inc_pulm_100k, inc_ep_100k) %>%
  pivot_longer(cols = c(inc_pulm_100k, `inc_ep_100k`)) %>%
  mutate(name = case_when(name == "inc_pulm_100k" ~ "Pulmonary TB",
                          name == "inc_ep_100k" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

Change in case notification rates pre-intervention

5.2 TB case notification rates by Division


division_inc <- division_pops %>%
  left_join(cases_by_division)
Joining with `by = join_by(division, year)`
division_inc <- division_inc %>%
  mutate(inc_100k = cases/total_population*100000)

division_inc %>%
  select(year, division, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

division_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB case notification rates by Ward

Here we will filter out the institutions and harbour from the denominators, as we don’t have reliable population denominators for them.


ward_inc <- ward_pops %>%
  left_join(cases_by_ward)
Joining with `by = join_by(ward, year, year2)`
ward_inc <- ward_inc %>%
  mutate(inc_100k = cases/population_without_inst_ship*100000)

ward_inc %>%
  select(year, ward, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

ward_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Incidence (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA
NA
NA

On a map


st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(legend.position = "top",
        legend.key.width = unit(2, "cm"),
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`

6. TB Mortality

6.1 Overall Mortality

Import the TB mortality data.

First, overall deaths. Note that in the original reports, we have a pulmonary TB death rate per million for all years, and numbers of pulmonary TB deaths for each year apart from 1950.


#get the overall mortality sheets
deaths_sheets <- enframe(all_sheets) %>%
  filter(grepl("deaths", value)) %>%
  pull(value)


overall_deaths <- map_df(deaths_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

overall_deaths %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA
NA

Plot the raw numbers of pulmonary deaths


overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_deaths)) +
  geom_line(colour = "#DE0D92") +
  geom_point(colour = "#DE0D92") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  labs(y="Pulmonary TB deaths per year",
       x = "Year",
       title = "Numbers of pulmonary TB deaths",
       subtitle = "Glasgow, 1950-1963",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: no data for 1950") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

NA
NA

Now the incidence of pulmonary TB death

overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_death_rate_per_100k)) +
  geom_line(colour = "#4D6CFA") +
  geom_point(colour = "#4D6CFA") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(y="Annual incidence of death (per 100,000)",
       x = "Year",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s7.png"), width=10)
Saving 10 x 4.5 in image

6. Table 1

Make Table 1 here, and save for publication.


overall_pops %>% 
  select(year, total_population) %>%
  left_join(overall_inc %>%
              select(year, 
                     pulmonary_notifications, inc_pulm_100k,
                     `non-pulmonary_notifications`, inc_ep_100k,
                     total_notifications, inc_100k)) %>%
  left_join(overall_deaths %>%
              select(year,
                     pulmonary_deaths, pulmonary_death_rate_per_100k)) %>%
  mutate(across(where(is.numeric) & !(year),  ~round(., digits=1))) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) 
Joining with `by = join_by(year)`Joining with `by = join_by(year)`

Prepare the datasets for modelling


mdata <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()


mdata_extrapulmonary <- ward_inc %>%
  filter(tb_type=="Non-Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup() %>% 
  filter(year<=1961) #no data for 1962 and 1963


#scaffold for overall predictions
overall_scaffold <- mdata %>%
    select(year, year2, y_num, acf_period, population_without_inst_ship, ward, cases) %>%
    group_by(year, year2, y_num, acf_period) %>%
    summarise(population_without_inst_ship = sum(population_without_inst_ship),
              cases = sum(cases)) %>%
    ungroup() %>%
    mutate(inc_100k = cases/population_without_inst_ship*100000) %>%
    left_join(mdata_extrapulmonary %>% group_by(year) %>%
                summarise(cases_extrapulmonary = sum(cases))) %>%
    mutate(inc_100k_extrapulmonary = cases_extrapulmonary/population_without_inst_ship*100000)
`summarise()` has grouped output by 'year', 'year2', 'y_num'. You can override using the `.groups` argument.Joining with `by = join_by(year)`

7. Pulmonary TB model

7.1 Fit the model and priors

This models the case notification rate over time, with a step change for the intervention, and slope change after the intervention.

Work on the priors a bit. We will build up from less complex to more complex.

  1. intercept only, to predict count of cases

at the intercept, we expect somewhere around 2500. We will set the standard deviation to both 0.5 and 1 to check what it looks like

# 
# c(prior(lognormal(7.600902, 0.5)), #log(2500) = 7.600902
#   prior(lognormal(7.600902, 1))) %>% 
#   parse_dist() %>% 
#   
#   ggplot(aes(y = prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(.5, .95)) +
#   scale_y_discrete(NULL, labels = str_c("lognormal(log(2000), ", c(0.5, 1), ")"),
#                    expand = expansion(add = 0.1)) +
#   xlab(expression(exp(italic(p)(beta[0])))) +
#   coord_cartesian(xlim = c(0,15000))
# 
# 
# prior(gamma(1, 0.01)) %>%
#   parse_dist() %>%
#   ggplot(aes(y=prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(0.5, 0.95))
# 
# #now fit to a model, and plot some prior realisations
# 
# m_prior1 <- brm(
#   cases ~ 0 + Intercept,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape)
# )
# 
# add_epred_draws(object=m_prior1,
#                 newdata = tibble(intercept=1)) %>%
#   ggplot(aes(x=intercept, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(labels = comma)

Now try to add in a term for the effect of y_num. We anticpate that the number of cases will decline by about 1-5% per year. However, as we are pretty uncertain about this, we will just encode a weakly regularising prior to restrict the year size to sensible ranges.

# 
# 
# m_prior2 <- brm(
#   cases ~ 0 + Intercept + y_num,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b, coef = y_num)
# )
# 
# add_epred_draws(object=m_prior2,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)

Now we want to add in a prior for the effect of the acf_intervention. We anticipate the peak to be anywhere between no effect, and a tripling

# 
# m_prior3 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b, coef = y_num) +
#           prior(normal(0, 0.001), class = b)
# )
# 
# 
# add_epred_draws(object=m_prior3,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(labels = comma)
# 

Now we look and see what it looks like with the interactions

# 
# m_prior4 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period + y_num:acf_period,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2500), 1), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b)
# )
# 
# add_epred_draws(object=m_prior4,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# 

Now try adding in the random intercepts


# c(prior(lognormal(3.912023, 0.5)), #log(50) = 3.912023
#   prior(lognormal(3.912023, 1))) %>% 
#   parse_dist() %>% 
#   
#   ggplot(aes(y = prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(.5, .95)) +
#   scale_y_discrete(NULL, labels = str_c("lognormal(log(50), ", c(0.5, 1), ")"),
#                    expand = expansion(add = 0.1)) +
#   xlab(expression(exp(italic(p)(beta[0])))) +
#   coord_cartesian(xlim = c(0,400))
# 
# 
# m_prior5 <- brm(
#   cases ~ y_num + acf_period + y_num:acf_period + ( 1 | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(normal(log(50), 1), class = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b) +
#           prior(exponential(1), class=sd)
# )
# 
# 
# add_epred_draws(object=m_prior5,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# add_epred_draws(object=m_prior5,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma) +
#   facet_wrap(ward~.)

And add in the random slopes

# 
# m_prior6 <- brm(
#   cases ~ 1 + y_num + acf_period + y_num:acf_period + (1 + y_num*acf_period | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.1), class = b) +
#           prior(exponential(1), class=sd) +
#           prior(lkj(2), class=cor)
# )
# 
# 
# 
# m_prior6 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period + y_num:acf_period + ( y_num*acf_period | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(normal(log(50), 1), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b) +
#           prior(exponential(100), class=sd) +
#           prior(lkj(2), class=cor)
# )


# add_epred_draws(object=m_prior6,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# add_epred_draws(object=m_prior6,
#                 newdata = mdata,
#                 re_formula = ~( 1 + y_num + acf_period | ward)) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma) +
#   facet_wrap(ward~.)
# 
# plot_counterfactual(model_data = overall_scaffold, model=m_prior6, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, re_formula = NA)
# 
# plot_counterfactual(model_data = mdata, model=m_prior6, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, grouping_var = ward, ward,
#                     re_formula = ~( 1 + y_num + acf_period | ward))

Issue here is the non-centred parameterisation of the intercept prior… Feel like this is a more interpretable way to set priors… but will revert to centred parameterisation for the meantime.

# m_centered_prior <- brm(
#   cases ~ 1 + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
#                   data = mdata,
#                   family = negbinomial(),
#                   seed = 1234,
#                   chains = 4, cores = 4,
#                   prior = prior(normal(0,1000), class = Intercept) +
#                           prior(gamma(0.01, 0.01), class = shape) +
#                           prior(normal(0, 1), class = b) +
#                           prior(exponential(1), class=sd) +
#                           prior(lkj(2), class=cor),
#                   sample_prior = "only")
# 
# plot(m_centered_prior)
# 
# plot_counterfactual(model_data = overall_scaffold, model=m_centered_prior, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, re_formula = NA)
# 
# plot_counterfactual(model_data = mdata, model=m_centered_prior, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, grouping_var = ward, ward,
#                     re_formula = ~( 1 + y_num*acf_period | ward))

Look at the mean and variance of counts (counts of pulmonary notifications are what we are predicting)


#Mean of counts per year
mean(mdata$cases)
[1] 48.32819
#variance of counts per year
var(mdata$cases)
[1] 915.5749

Quite a bit of over-dispersion here, so negative binomial distribution might be a better choice of distributional family than Poisson.

Fit the model with the data

#check model diagnostics
summary(m_pulmonary)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ 1 + y_num * acf_period + (1 + y_num * acf_period | ward) + offset(log(population_without_inst_ship)) 
   Data: mdata (Number of observations: 518) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Group-Level Effects: 
~ward (Number of levels: 37) 
                                                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)                                             0.25      0.03     0.19     0.32 1.00     1676     2545
sd(y_num)                                                 0.02      0.01     0.01     0.03 1.00      910      767
sd(acf_periodb.acf)                                       0.06      0.04     0.00     0.16 1.00     1539     1541
sd(acf_periodc.postMacf)                                  0.11      0.06     0.01     0.24 1.00      792     1493
sd(y_num:acf_periodb.acf)                                 0.01      0.01     0.00     0.02 1.00     1534     1834
sd(y_num:acf_periodc.postMacf)                            0.01      0.01     0.00     0.02 1.00      586     1243
cor(Intercept,y_num)                                     -0.45      0.19    -0.75    -0.00 1.00     2105     1928
cor(Intercept,acf_periodb.acf)                           -0.23      0.29    -0.71     0.38 1.00     3192     2501
cor(y_num,acf_periodb.acf)                               -0.05      0.27    -0.55     0.49 1.00     5900     3316
cor(Intercept,acf_periodc.postMacf)                      -0.14      0.24    -0.58     0.37 1.00     3998     2877
cor(y_num,acf_periodc.postMacf)                           0.10      0.26    -0.41     0.58 1.00     3393     3029
cor(acf_periodb.acf,acf_periodc.postMacf)                 0.07      0.28    -0.47     0.58 1.00     2092     2824
cor(Intercept,y_num:acf_periodb.acf)                     -0.24      0.28    -0.72     0.36 1.00     3639     3063
cor(y_num,y_num:acf_periodb.acf)                         -0.05      0.27    -0.55     0.49 1.00     5688     3327
cor(acf_periodb.acf,y_num:acf_periodb.acf)               -0.05      0.28    -0.58     0.49 1.00     4612     2835
cor(acf_periodc.postMacf,y_num:acf_periodb.acf)           0.07      0.27    -0.46     0.57 1.00     3873     3333
cor(Intercept,y_num:acf_periodc.postMacf)                -0.02      0.25    -0.50     0.47 1.00     5667     3341
cor(y_num,y_num:acf_periodc.postMacf)                    -0.03      0.28    -0.54     0.53 1.00     2983     2512
cor(acf_periodb.acf,y_num:acf_periodc.postMacf)           0.06      0.27    -0.48     0.56 1.00     2562     2754
cor(acf_periodc.postMacf,y_num:acf_periodc.postMacf)     -0.07      0.29    -0.61     0.49 1.00     2466     2876
cor(y_num:acf_periodb.acf,y_num:acf_periodc.postMacf)     0.04      0.28    -0.49     0.57 1.00     2347     3061

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -6.14      0.05    -6.23    -6.05 1.00     1002     1503
y_num                         -0.02      0.01    -0.03    -0.01 1.00     3453     2947
acf_periodb.acf                0.03      0.99    -1.92     1.95 1.00     3857     3041
acf_periodc.postMacf           0.04      0.11    -0.16     0.25 1.00     4109     3148
y_num:acf_periodb.acf          0.08      0.12    -0.16     0.33 1.00     3855     3090
y_num:acf_periodc.postMacf    -0.05      0.01    -0.07    -0.03 1.00     3998     2938

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    92.69     20.80    60.69   140.57 1.00     3627     2972

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

Nicer version of trace plots for supplemental material

as_draws_df(m_pulmonary) %>% 
  bayesplot::mcmc_rank_overlay(pars = vars(b_Intercept:shape),
             facet_args = list(ncol = 4)) +
  scale_colour_scico_d(palette = "managua", name = "Chain") +
  theme_ggdist()+
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "top")
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

Nicer version of table of parameters for supplement

7.2 Summarise change in CNRs

Summarise the posterior in graphical form


f1b <- plot_counterfactual(model_data = overall_scaffold, model = m_pulmonary, 
                           population_denominator = population_without_inst_ship, outcome = inc_100k, grouping_var=NULL,
                           re_formula = NA)
  
f1b

Make this into a figure combined with the map of empirical data

ggsave(here("figures/f1.png"), width=7)
Saving 7 x 7 in image

Summary of change in notifications numerically

7.3 Compared to counterfactual

Numbers of pulmonary TB cases averted compared to counterfactual per year.

overall_pulmonary_counterf <- calculate_counterfactual(model_data = overall_scaffold, model=m_pulmonary, population_denominator = population_without_inst_ship)
Joining with `by = join_by(year, population_without_inst_ship, .draw)`Joining with `by = join_by(.draw)`
Error in `mutate()`:
ℹ In argument: `diff_inc100k = .epred - .epred_inc_counterf`.
Caused by error:
! object '.epred_inc_counterf' not found
Backtrace:
  1. global calculate_counterfactual(...)
  8. dplyr:::mutate.data.frame(...)
  9. dplyr:::mutate_cols(.data, dplyr_quosures(...), by)
 11. dplyr:::mutate_col(dots[[i]], data, mask, new_columns)
 12. mask$eval_all_mutate(quo)
 13. dplyr (local) eval()

Total pulmonary TB cases averted between 1958 and 1963

7.4 Correlation between RR.peak, RR.level, and RR.slope

What are the correlations between peak, level, and slope?


#RR.peak histogram
a <- overall_change$peak_draws %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.peak",
       y="")

#RR. level histogram
b <- overall_change$level_draws  %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.level",
       y="")

#RR.slope histogram
c <- overall_change$slope_draws %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +  
  #scale_x_continuous(limits = c(0, 6)) +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.slope",
       y="")


#Correlation between RR.peak and RR.level
cor_rr_peak_rr_level <- round(cor(pluck(overall_change$peak_draws$estimate), pluck(overall_change$level_draws$estimate)), digits = 2)

#Correlation between RR.peak and RR.slope
cor_rr_peak_rr_slope <- round(cor(pluck(overall_change$peak_draws$estimate), pluck(overall_change$slope_draws$estimate)), digits = 2)

#Correlation between RR.level and RR.slope
cor_rr_level_rr_slope <- round(cor(pluck(overall_change$level_draws$estimate), pluck(overall_change$slope_draws$estimate)), digits = 2)


#plot of correlation between RR.peak and RR.level
d <- bind_cols(RR.peak=pluck(overall_change$peak_draws$estimate), 
          RR.level =pluck(overall_change$level_draws$estimate)) %>%
  ggplot(aes(y=RR.peak, x = RR.level)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick", method = "lm") +
  geom_text(aes(y=2.2, x=0.58, label=cor_rr_peak_rr_level), colour="firebrick")  +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

#plot of correlation between RR.peak and RR.slope
e <- bind_cols(RR.peak=pluck(overall_change$peak_draws$estimate), 
          RR.slope =pluck(overall_change$slope_draws$estimate)) %>%
  ggplot(aes(y=RR.peak, x = RR.slope)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick", method = "lm") +
  geom_text(aes(y=2.1, x=0.65, label=cor_rr_peak_rr_slope), colour="firebrick")  +
  #scale_x_continuous(limits = c(0, 6)) +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

#plot of correlation between RR.level and RR.slope
f <- bind_cols(RR.level=pluck(overall_change$level_draws$estimate), 
          RR.slope =pluck(overall_change$slope_draws$estimate)) %>%
  ggplot(aes(y=RR.level, x = RR.slope)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick", method = "lm") +
  geom_text(aes(y=0.75, x=0.65, label=cor_rr_level_rr_slope), colour="firebrick")  +  
  #scale_x_continuous(limits = c(0, 6)) +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))


(plot_spacer() + plot_spacer() + c) /
  (plot_spacer() + b + f) /
  (a + d + e)

ggsave(here("figures/s6.png"), width=8, height=8)

NA
NA
NA

7.5 Ward level pulmonary TB estimates

Plot the counterfactual at ward level

Summary of change in notifications at ward level

Calculate the counterfactual per ward


ward_pulmonary_counterf <- calculate_counterfactual(model_data = mdata, model=m_pulmonary, 
                                                    population_denominator = population_without_inst_ship,
                                                    grouping_var = ward, re_formula=~(1 + y_num*acf_period | ward))
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.Joining with `by = join_by(year, population_without_inst_ship, .draw, ward)`Joining with `by = join_by(.draw, ward)`
ward_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

Overall counterfactual per ward


ward_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

8. Extra-pulmonary TB notifications

Now we will model the extra-pulmonary TB notification rate. Struggling a bit with negative binomial model, so revert to Poisson.

8.1 Fit the model


m_extrapulmonary <- brm(
  cases ~ 1 + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
                  data = mdata_extrapulmonary,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4,
                  prior = prior(normal(0,1000), class = Intercept) +
                          prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 1), class = b) +
                          prior(exponential(1), class=sd) +
                          prior(lkj(2), class=cor))
Compiling Stan program...
Start sampling
starting worker pid=12801 on localhost:11828 at 13:47:21.663
starting worker pid=12815 on localhost:11828 at 13:47:21.863
starting worker pid=12829 on localhost:11828 at 13:47:22.069
starting worker pid=12843 on localhost:11828 at 13:47:22.283

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 0.000295 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 2.95 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 0.00027 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 2.7 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 0.000738 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 7.38 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 0.000241 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 2.41 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 18.538 seconds (Warm-up)
Chain 3:                8.306 seconds (Sampling)
Chain 3:                26.844 seconds (Total)
Chain 3: 
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 18.801 seconds (Warm-up)
Chain 2:                8.357 seconds (Sampling)
Chain 2:                27.158 seconds (Total)
Chain 2: 
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 18.629 seconds (Warm-up)
Chain 4:                8.394 seconds (Sampling)
Chain 4:                27.023 seconds (Total)
Chain 4: 
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 18.367 seconds (Warm-up)
Chain 1:                12.209 seconds (Sampling)
Chain 1:                30.576 seconds (Total)
Chain 1: 
summary(m_extrapulmonary)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ 1 + y_num * acf_period + (1 + y_num * acf_period | ward) + offset(log(population_without_inst_ship)) 
   Data: mdata_extrapulmonary (Number of observations: 444) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Group-Level Effects: 
~ward (Number of levels: 37) 
                                                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)                                             0.33      0.06     0.23     0.46 1.00     1503     2462
sd(y_num)                                                 0.02      0.01     0.00     0.04 1.00      451      936
sd(acf_periodb.acf)                                       0.11      0.09     0.00     0.32 1.00     2251     1370
sd(acf_periodc.postMacf)                                  0.12      0.09     0.01     0.33 1.00     1677     1902
sd(y_num:acf_periodb.acf)                                 0.01      0.01     0.00     0.04 1.00     1884     1613
sd(y_num:acf_periodc.postMacf)                            0.02      0.01     0.00     0.04 1.00     1028     1648
cor(Intercept,y_num)                                     -0.10      0.30    -0.64     0.52 1.00     2231     2364
cor(Intercept,acf_periodb.acf)                           -0.01      0.32    -0.61     0.60 1.00     4995     2686
cor(y_num,acf_periodb.acf)                               -0.00      0.33    -0.65     0.62 1.00     3912     2498
cor(Intercept,acf_periodc.postMacf)                      -0.07      0.32    -0.66     0.58 1.00     3742     2610
cor(y_num,acf_periodc.postMacf)                          -0.04      0.33    -0.66     0.61 1.00     3320     2566
cor(acf_periodb.acf,acf_periodc.postMacf)                 0.02      0.34    -0.60     0.67 1.00     2917     3101
cor(Intercept,y_num:acf_periodb.acf)                     -0.01      0.33    -0.63     0.61 1.00     4615     2927
cor(y_num,y_num:acf_periodb.acf)                         -0.02      0.33    -0.63     0.63 1.00     3487     2438
cor(acf_periodb.acf,y_num:acf_periodb.acf)               -0.08      0.34    -0.71     0.57 1.00     3404     3133
cor(acf_periodc.postMacf,y_num:acf_periodb.acf)           0.02      0.34    -0.63     0.66 1.00     3443     3302
cor(Intercept,y_num:acf_periodc.postMacf)                -0.16      0.31    -0.70     0.48 1.00     3286     2619
cor(y_num,y_num:acf_periodc.postMacf)                    -0.05      0.33    -0.67     0.57 1.00     2923     2777
cor(acf_periodb.acf,y_num:acf_periodc.postMacf)           0.03      0.33    -0.60     0.65 1.00     2242     2945
cor(acf_periodc.postMacf,y_num:acf_periodc.postMacf)     -0.08      0.34    -0.71     0.61 1.00     2626     2612
cor(y_num:acf_periodb.acf,y_num:acf_periodc.postMacf)     0.01      0.33    -0.62     0.64 1.00     2469     3425

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -7.93      0.08    -8.08    -7.78 1.00     1464     2154
y_num                         -0.09      0.01    -0.12    -0.07 1.00     4426     2523
acf_periodb.acf                0.03      0.98    -1.94     1.94 1.00     2670     2671
acf_periodc.postMacf          -0.35      0.39    -1.12     0.40 1.00     2594     2610
y_num:acf_periodb.acf         -0.02      0.12    -0.26     0.23 1.00     2656     2529
y_num:acf_periodc.postMacf     0.02      0.04    -0.06     0.10 1.00     2524     2686

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    91.55     63.18    26.77   264.23 1.00     3449     2865

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_extrapulmonary)

pp_check(m_extrapulmonary, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

8.2 Summary of change

Summarise in plot

ggsave(here("figures/s7.png"), width=10)
Saving 10 x 7 in image

Summarise numerically.

8.3 Compared to counterfactual

Numbers of extra-pulmonary TB cases averted overall.


overall_ep_counterf <- calculate_counterfactual(model_data = mdata_extrapulmonary, model=m_extrapulmonary, 
                                               population_denominator = population_without_inst_ship)
Joining with `by = join_by(year, population_without_inst_ship, .draw)`Joining with `by = join_by(.draw)`
overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

Total extrapulmonary TB cases averted between 1958 and 1963


overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

Make into Table 2

bind_rows(
overall_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(model = "PTB_ward"),

overall_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(model = "PTB_overall"),

overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(model = "EPTB"),

overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(model = "EPTB overall")

) %>%
  select(model, year, diff_inc100k, diff_inc100k.lower:rr_inc100k.upper, 
         cases_averted:cases_averted.upper,
         pct_change:pct_change.upper) %>%
  transmute(model=model, year=year,
            diff_cnr = glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr = glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"),
            cases_averted = glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"))
NA
NA
NA

8.4 Ward-level extra-pulmonary summaries

Ward-level extra-pulmonary estimates in graphical form.

Numerical summary.


ward_change_extrapulmonary <- summarise_change(model_data = mdata_extrapulmonary, model = m_extrapulmonary, 
                                population_denominator = population_without_inst_ship, grouping_var=ward,
                                re_formula = ~(y_num*acf_period | ward)) 
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw', 'acf_period'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
ward_change_extrapulmonary  %>%
  keep(names(.) %in% tokeep) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA
NA
NA

9. Age-sex model

9.1 FIt the model

Fit the model

(Not rewritten the functions for this yet)


mdata_age_sex <- cases_by_age_sex %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(year2 = year+0.5) %>%
  group_by(age, sex) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

m_age_sex <- brm(
  cases ~ y_num + (acf_period)*(age*sex) + (acf_period:y_num)*(age*sex),
                  data = mdata_age_sex,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = prior(normal(0,1), class = Intercept) +
                          prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 1), class = b))
Compiling Stan program...
Start sampling
starting worker pid=13006 on localhost:11828 at 13:49:46.708
starting worker pid=13020 on localhost:11828 at 13:49:46.924
starting worker pid=13034 on localhost:11828 at 13:49:47.120
starting worker pid=13048 on localhost:11828 at 13:49:47.308

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 6.1e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.61 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 6.1e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.61 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 5.6e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.56 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 0.000141 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 1.41 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 14.272 seconds (Warm-up)
Chain 3:                16.416 seconds (Sampling)
Chain 3:                30.688 seconds (Total)
Chain 3: 
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 15.326 seconds (Warm-up)
Chain 2:                17.167 seconds (Sampling)
Chain 2:                32.493 seconds (Total)
Chain 2: 
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 14.691 seconds (Warm-up)
Chain 1:                18.176 seconds (Sampling)
Chain 1:                32.867 seconds (Total)
Chain 1: 
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 15.351 seconds (Warm-up)
Chain 4:                17.852 seconds (Sampling)
Chain 4:                33.203 seconds (Total)
Chain 4: 
summary(m_age_sex)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + (acf_period) * (age * sex) + (acf_period:y_num) * (age * sex) 
   Data: mdata_age_sex (Number of observations: 224) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                                         Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                                    4.43      0.11     4.21     4.65 1.00     1202     2133
y_num                                       -0.17      0.03    -0.23    -0.11 1.00     1181     2021
acf_periodb.acf                             -0.02      1.01    -1.96     1.93 1.00     5991     3250
acf_periodc.postMacf                        -0.48      0.33    -1.13     0.14 1.00     2320     2790
age06_15                                     0.62      0.15     0.33     0.93 1.00     1767     2657
age16_25                                     1.85      0.13     1.58     2.11 1.00     1470     2805
age26_35                                     1.12      0.14     0.85     1.39 1.00     1487     2364
age36_45                                     0.27      0.15    -0.04     0.56 1.00     1681     2047
age46_55                                    -0.63      0.17    -0.98    -0.30 1.00     1884     2918
age56_65                                    -1.08      0.19    -1.46    -0.70 1.00     2432     2970
age65P                                      -1.65      0.22    -2.06    -1.23 1.00     2780     3021
sexM                                         0.15      0.15    -0.15     0.45 1.00     1076     1754
age06_15:sexM                               -0.41      0.21    -0.83    -0.01 1.00     1539     2699
age16_25:sexM                               -0.56      0.18    -0.92    -0.20 1.00     1336     2185
age26_35:sexM                               -0.32      0.19    -0.69     0.05 1.00     1463     2338
age36_45:sexM                                0.25      0.20    -0.14     0.66 1.00     1623     2124
age46_55:sexM                                1.16      0.22     0.73     1.59 1.00     1728     2125
age56_65:sexM                                1.14      0.24     0.67     1.62 1.00     2042     2298
age65P:sexM                                  1.02      0.26     0.50     1.54 1.00     2229     2955
acf_periodb.acf:age06_15                     0.04      0.97    -1.83     1.98 1.00     7161     3192
acf_periodc.postMacf:age06_15               -0.61      0.52    -1.62     0.44 1.00     3634     3393
acf_periodb.acf:age16_25                     0.03      1.00    -1.94     2.01 1.00     7692     2619
acf_periodc.postMacf:age16_25                0.72      0.42    -0.09     1.56 1.00     3055     3053
acf_periodb.acf:age26_35                     0.03      1.03    -1.97     1.99 1.00     7987     2727
acf_periodc.postMacf:age26_35                0.65      0.43    -0.20     1.51 1.00     3000     2989
acf_periodb.acf:age36_45                     0.06      1.00    -1.91     2.12 1.01     7678     3152
acf_periodc.postMacf:age36_45                0.74      0.46    -0.18     1.65 1.00     3439     3041
acf_periodb.acf:age46_55                     0.06      0.98    -1.84     1.99 1.00     7877     2591
acf_periodc.postMacf:age46_55                0.84      0.48    -0.09     1.80 1.00     3588     3242
acf_periodb.acf:age56_65                     0.05      0.99    -1.99     2.00 1.00     7601     2783
acf_periodc.postMacf:age56_65                0.61      0.52    -0.42     1.63 1.00     3588     2823
acf_periodb.acf:age65P                       0.06      0.98    -1.92     1.97 1.00     6551     3056
acf_periodc.postMacf:age65P                  0.95      0.53    -0.09     2.01 1.00     3685     3135
acf_periodb.acf:sexM                        -0.00      0.99    -1.95     1.88 1.00     7239     3015
acf_periodc.postMacf:sexM                   -0.07      0.38    -0.82     0.67 1.00     2234     2809
y_num:acf_periodb.acf                       -0.10      0.13    -0.35     0.16 1.00     5968     3007
y_num:acf_periodc.postMacf                   0.04      0.04    -0.03     0.12 1.00     1947     2248
acf_periodb.acf:age06_15:sexM                0.00      0.98    -1.98     1.90 1.00     8260     3245
acf_periodc.postMacf:age06_15:sexM          -0.56      0.65    -1.84     0.72 1.00     4807     3353
acf_periodb.acf:age16_25:sexM                0.01      0.96    -1.84     1.92 1.00     6900     3115
acf_periodc.postMacf:age16_25:sexM           0.65      0.53    -0.42     1.68 1.00     4022     3462
acf_periodb.acf:age26_35:sexM                0.02      0.97    -1.85     1.94 1.00     8452     3036
acf_periodc.postMacf:age26_35:sexM           0.40      0.53    -0.68     1.45 1.00     3126     2740
acf_periodb.acf:age36_45:sexM               -0.01      0.99    -1.93     1.96 1.00     6626     3024
acf_periodc.postMacf:age36_45:sexM           0.11      0.55    -1.00     1.14 1.00     3777     3023
acf_periodb.acf:age46_55:sexM               -0.00      0.99    -1.93     1.94 1.00     7270     3024
acf_periodc.postMacf:age46_55:sexM           0.67      0.56    -0.41     1.80 1.00     3708     3132
acf_periodb.acf:age56_65:sexM                0.00      1.00    -1.97     1.94 1.00     6891     3364
acf_periodc.postMacf:age56_65:sexM           0.37      0.59    -0.77     1.53 1.00     4009     2948
acf_periodb.acf:age65P:sexM                  0.00      0.98    -1.88     1.90 1.00     8469     2945
acf_periodc.postMacf:age65P:sexM             0.29      0.60    -0.89     1.47 1.00     4122     3353
y_num:acf_perioda.preMacf:age06_15           0.02      0.04    -0.05     0.10 1.00     1562     2338
y_num:acf_periodb.acf:age06_15               0.15      0.13    -0.11     0.39 1.00     7055     3095
y_num:acf_periodc.postMacf:age06_15          0.08      0.05    -0.01     0.17 1.00     3210     3231
y_num:acf_perioda.preMacf:age16_25           0.13      0.03     0.06     0.19 1.00     1326     1893
y_num:acf_periodb.acf:age16_25               0.25      0.13    -0.01     0.51 1.00     7194     3014
y_num:acf_periodc.postMacf:age16_25         -0.04      0.04    -0.12     0.04 1.00     2497     3173
y_num:acf_perioda.preMacf:age26_35           0.15      0.03     0.08     0.22 1.00     1387     2037
y_num:acf_periodb.acf:age26_35               0.31      0.14     0.05     0.58 1.00     7412     2758
y_num:acf_periodc.postMacf:age26_35          0.02      0.04    -0.06     0.10 1.00     2474     3219
y_num:acf_perioda.preMacf:age36_45           0.17      0.04     0.10     0.25 1.00     1486     2320
y_num:acf_periodb.acf:age36_45               0.40      0.13     0.13     0.66 1.00     7379     3168
y_num:acf_periodc.postMacf:age36_45          0.06      0.04    -0.02     0.14 1.00     2873     2942
y_num:acf_perioda.preMacf:age46_55           0.20      0.04     0.11     0.28 1.00     1704     2513
y_num:acf_periodb.acf:age46_55               0.44      0.13     0.18     0.70 1.00     6789     2642
y_num:acf_periodc.postMacf:age46_55          0.10      0.04     0.01     0.18 1.00     3029     3481
y_num:acf_perioda.preMacf:age56_65           0.18      0.05     0.08     0.27 1.00     2054     2885
y_num:acf_periodb.acf:age56_65               0.39      0.13     0.13     0.67 1.00     6479     3045
y_num:acf_periodc.postMacf:age56_65          0.11      0.05     0.02     0.20 1.00     2867     3111
y_num:acf_perioda.preMacf:age65P             0.23      0.05     0.13     0.33 1.00     2476     2795
y_num:acf_periodb.acf:age65P                 0.43      0.13     0.17     0.69 1.00     5858     3205
y_num:acf_periodc.postMacf:age65P            0.11      0.05     0.02     0.21 1.00     3223     3331
y_num:acf_perioda.preMacf:sexM               0.02      0.04    -0.06     0.10 1.00     1060     1539
y_num:acf_periodb.acf:sexM                  -0.03      0.14    -0.31     0.23 1.00     6443     3067
y_num:acf_periodc.postMacf:sexM             -0.01      0.04    -0.09     0.06 1.00     2046     2564
y_num:acf_perioda.preMacf:age06_15:sexM     -0.00      0.05    -0.10     0.10 1.00     1500     2633
y_num:acf_periodb.acf:age06_15:sexM          0.04      0.14    -0.23     0.33 1.00     6732     2680
y_num:acf_periodc.postMacf:age06_15:sexM     0.10      0.06    -0.02     0.21 1.00     4164     3286
y_num:acf_perioda.preMacf:age16_25:sexM     -0.01      0.05    -0.09     0.09 1.00     1237     2170
y_num:acf_periodb.acf:age16_25:sexM          0.06      0.14    -0.22     0.33 1.00     5883     2903
y_num:acf_periodc.postMacf:age16_25:sexM    -0.01      0.05    -0.11     0.09 1.00     3107     3337
y_num:acf_perioda.preMacf:age26_35:sexM     -0.01      0.05    -0.11     0.08 1.00     1357     1998
y_num:acf_periodb.acf:age26_35:sexM          0.05      0.14    -0.22     0.32 1.00     6502     2958
y_num:acf_periodc.postMacf:age26_35:sexM    -0.01      0.05    -0.10     0.09 1.00     2654     3020
y_num:acf_perioda.preMacf:age36_45:sexM     -0.02      0.05    -0.12     0.08 1.00     1416     2091
y_num:acf_periodb.acf:age36_45:sexM          0.00      0.14    -0.27     0.27 1.00     5693     2683
y_num:acf_periodc.postMacf:age36_45:sexM    -0.00      0.05    -0.10     0.10 1.00     3041     2778
y_num:acf_perioda.preMacf:age46_55:sexM     -0.01      0.05    -0.12     0.09 1.00     1537     2282
y_num:acf_periodb.acf:age46_55:sexM         -0.00      0.14    -0.27     0.27 1.00     6286     3013
y_num:acf_periodc.postMacf:age46_55:sexM    -0.07      0.05    -0.17     0.03 1.00     3143     2800
y_num:acf_perioda.preMacf:age56_65:sexM      0.05      0.06    -0.06     0.16 1.00     1758     2174
y_num:acf_periodb.acf:age56_65:sexM          0.07      0.14    -0.21     0.35 1.00     6312     3291
y_num:acf_periodc.postMacf:age56_65:sexM     0.01      0.05    -0.09     0.12 1.00     3364     2507
y_num:acf_perioda.preMacf:age65P:sexM       -0.00      0.06    -0.12     0.12 1.00     2029     2775
y_num:acf_periodb.acf:age65P:sexM            0.08      0.14    -0.19     0.35 1.00     6610     2481
y_num:acf_periodc.postMacf:age65P:sexM       0.01      0.06    -0.10     0.12 1.00     3533     3170

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape   198.71     63.50   104.03   349.06 1.00     2336     2371

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_age_sex)

pp_check(m_age_sex, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

conditional_effects(m_age_sex)

Summarise posterior

ggsave(here("figures/s9.png"), height=10)
Saving 7 x 10 in image

9.2 Summary of impact of intervention

Calculate summary effects

slope_draws_age_sex <- add_epred_draws(newdata = out_age_sex_3,
                  object = m_age_sex) %>%
        arrange(y_num) %>%
        ungroup() %>%
        group_by(.draw, y_num, age, sex) %>%
        summarise(slope = last(.epred)/first(.epred)) %>%
        ungroup() %>%
        group_by(.draw, age, sex) %>%
        summarise(estimate = last(slope)/first(slope)) %>%
        mutate(measure = "RR.slope")
`summarise()` has grouped output by '.draw', 'y_num', 'age'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw', 'age'. You can override using the `.groups` argument.

Numerical summary of these summary results

As a figure


peak_g_age_sex <- peak_summary_age_sex %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_hline(aes(yintercept=1), linetype=2)+
  geom_pointrange(aes(x=age, y=estimate, ymin=.lower, ymax=.upper, group=sex, colour=sex, shape=sex),
                  position = position_dodge(width = 0.5)) +
  scale_colour_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  scale_shape(name="") +
  labs(x="",
       y="Relative rate (95% UI)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))

#level plot
level_g_age_sex <- level_summary_age_sex %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_hline(aes(yintercept=1), linetype=2)+
  geom_pointrange(aes(x=age, y=estimate, ymin=.lower, ymax=.upper, group=sex, colour=sex, shape=sex),
                  position = position_dodge(width = 0.5)) +
  scale_colour_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  scale_shape(name="") +
  labs(x="",
       y="Relative rate (95% UI)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))

#slope plot
slope_g_age_sex <- slope_summary_age_sex %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_hline(aes(yintercept=1), linetype=2)+
  geom_pointrange(aes(x=age, y=estimate, ymin=.lower, ymax=.upper, group=sex, colour=sex, shape=sex),
                  position = position_dodge(width = 0.5)) +
  scale_colour_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  scale_shape(name="") +
  labs(x="",
       y="Relative rate (95% UI)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))

9.3 Compared to counterfactual


counterfact_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(year, age, sex, .draw, .epred_counterf = .epred)
Adding missing grouping variables: `year2`, `y_num`, `acf_period`, `.row`
  
#Calcuate predicted number of cases per draw, then summarise.
post_change_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, age, sex, .draw, .epred) 
  
#for the overall period
counterfact_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred)  %>%
      group_by(age, sex, .draw) %>%
      summarise(.epred_counterf = sum(.epred)) %>%
      mutate(year = "Overall (1958-1963)")
Adding missing grouping variables: `year`, `year2`, `y_num`, `acf_period`, `.row``summarise()` has grouped output by 'age', 'sex'. You can override using the `.groups` argument.
  
#Calcuate incidence per draw, then summarise.
post_change_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred) %>%
      group_by(.draw, age, sex) %>%
      summarise(.epred = sum(.epred)) 
Adding missing grouping variables: `year`, `year2`, `y_num`, `acf_period`, `.row``summarise()` has grouped output by '.draw', 'age'. You can override using the `.groups` argument.
  
counter_post_overall_age_sex <-
  left_join(counterfact_overall_age_sex, post_change_overall_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 
Joining with `by = join_by(age, sex, .draw)`
age_sex_txt <- counter_post_overall_age_sex %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  transmute(year = as.character(year),
            sex = sex,
            age = age,
            cases_averted = glue::glue("{cases_averted}\n({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change}\n({pct_change.lower} to {pct_change.upper})"))


age_sex_txt %>% datatable()
NA
NA

counterfactual_g_age_sex <- counter_post_overall_age_sex %>% 
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(x = age, y=cases_averted, ymin=cases_averted.lower, ymax=cases_averted.upper, colour=sex, shape=sex), position=position_dodge(width=0.5)) + 
  scale_colour_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  scale_shape(name="") +
  scale_y_continuous(labels = comma) +
  labs(x="",
       y="Number (95% UI)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "bottom")

counterfactual_g_age_sex

Join together for Figure 3.

LS0tCnRpdGxlOiAiR2xhc2dvdyBUQiBBQ0YiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyAxLiBMaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKIyMjIyAxLjEgTGlicmFyaWVzCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMuCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobWFyZ2luYWxlZmZlY3RzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NpY28pCmxpYnJhcnkoZ2dkZW5zaXR5KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeSh1bml0cykKbGlicmFyeShnbHVlKQojbGlicmFyeShnZ3NuKQoKYGBgCgojIyMjIDEuMiBIZWxwZXIgZnVuY3Rpb25zCgpGdW5jdGlvbnMgdGhhdCB3ZSB3aWxsIHVzZSB0aHJvdWdob3V0IHRoZSBzY3JpcHQKCmBgYHtyfQojbGFiZWxsZXIgZm9yIHllYXJzCnllYXJfbGFiZWxzIDwtIGMoMTk1MDoxOTYzKQoKI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKI1NlZ21lbnQgZm9yIGdyYXBocyB0byBtYXRjaCBBQ0YgcGVyaW9kCmFjZl9zdGFydCA8LSBkZWNpbWFsX2RhdGUoeW1kKCIxOTU3LTAzLTExIikpCmFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKCmBgYAoKRnVuY3Rpb24gZm9yIGNvdW50ZXJmYWN0dWFsIHBsb3RzCgpgYGB7cn0KCgpwbG90X2NvdW50ZXJmYWN0dWFsIDwtIGZ1bmN0aW9uKG1vZGVsX2RhdGEsIG1vZGVsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yLCBvdXRjb21lLCBncm91cGluZ192YXI9TlVMTCwgcmVfZm9ybXVsYSwuLi4pewogIAogICNsYWJlbGxlciBmb3IgeWVhcnMKICB5ZWFyX2xhYmVscyA8LSBjKDE5NTA6MTk2MykKCiAgI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKICAjU2VnbWVudCBmb3IgZ3JhcGhzIHRvIG1hdGNoIEFDRiBwZXJpb2QKICBhY2Zfc3RhcnQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wMy0xMSIpKQogIGFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKICBzdW1tYXJ5IDwtIHt7bW9kZWxfZGF0YX19ICU+JQogICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7b3V0Y29tZX19LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIGFkZF9lcHJlZF9kcmF3cyh7e21vZGVsfX0sIHJlX2Zvcm11bGE9e3tyZV9mb3JtdWxhfX0pICU+JQogICAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaSgpICU+JQogICAgbXV0YXRlKC5lcHJlZF9pbmMgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAgLmVwcmVkX2luYy5sb3dlciA9IC5lcHJlZC5sb3dlci97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgICAuZXByZWRfaW5jLnVwcGVyID0gLmVwcmVkLnVwcGVyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpCgoKCiAgI2NyZWF0ZSB0aGUgY291bnRlcmZhY3R1YWwgKG5vIGludGVydmVudGlvbiksIGFuZCBzdW1tYXJpc2UKICAKICBjb3VudGVyZmFjdCA8LQogICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0ge3ttb2RlbF9kYXRhfX0gJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwge3tvdXRjb21lfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFjZl9wZXJpb2QgPSAiYS4gcHJlLWFjZiIpLCByZV9mb3JtdWxhPXt7cmVfZm9ybXVsYX19KSAlPiUKICAgIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoKSAlPiUKICAgIG11dGF0ZSguZXByZWRfaW5jID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgLmVwcmVkX2luYy5sb3dlciA9IC5lcHJlZC5sb3dlci97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMudXBwZXIgPSAuZXByZWQudXBwZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwKSAlPiUKICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpCiAgCgoKICAjcGxvdCB0aGUgaW50ZXJ2ZW50aW9uIGVmZmVjdApwIDwtIHN1bW1hcnkgJT4lCiAgICBkcm9wbGV2ZWxzKCkgJT4lCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX3JpYmJvbihhZXMoeW1pbj0uZXByZWRfaW5jLmxvd2VyLCB5bWF4PS5lcHJlZF9pbmMudXBwZXIsIHg9eWVhcjIsIGdyb3VwID0gYWNmX3BlcmlvZCwgZmlsbD1hY2ZfcGVyaW9kKSwgYWxwaGE9MC41KSArCiAgICBnZW9tX3JpYmJvbihkYXRhID0gY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgICBhZXMoeW1pbj0uZXByZWRfaW5jLmxvd2VyLCB5bWF4PS5lcHJlZF9pbmMudXBwZXIsIHg9eWVhcjIsIGZpbGw9IkNvdW50ZXJmYWN0dWFsIiksIGFscGhhPTAuNSkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBjb3VudGVyZmFjdCAlPiUgZmlsdGVyKHllYXI+PTE5NTYpLCAKICAgICAgICAgICAgICBhZXMoeT0uZXByZWRfaW5jLCB4PXllYXIyLCBjb2xvdXI9IkNvdW50ZXJmYWN0dWFsIikpICsKICAgIGdlb21fbGluZShhZXMoeT0uZXByZWRfaW5jLCB4PXllYXIyLCBncm91cD1hY2ZfcGVyaW9kLCAgY29sb3VyPWFjZl9wZXJpb2QpKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSB7e21vZGVsX2RhdGF9fSwgYWVzKHk9e3tvdXRjb21lfX0sIHg9eWVhcjIsIHNoYXBlPWFjZl9wZXJpb2QpLCBzaXplPTIpICsKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICAgIHRoZW1lX2dnZGlzdCgpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEsIGxpbWl0cyA9IGMoMCxOQSkpICsKICAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIiwgbmEudHJhbnNsYXRlID0gRikgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiLCBuYS50cmFuc2xhdGUgPSBGKSArCiAgICBzY2FsZV9zaGFwZV9kaXNjcmV0ZShuYW1lPSIiLCBuYS50cmFuc2xhdGUgPSBGKSArCiAgICBsYWJzKAogICAgICB4ID0gIlllYXIiLAogICAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgICApICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9OCwgYW5nbGUgPSA5MCwgaGp1c3Q9MSwgdmp1c3Q9MC41KSwKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCkpICsKICAgIGd1aWRlcyhzaGFwZT0ibm9uZSIpCgogICAgZmFjZXRfdmFycyA8LSB2YXJzKC4uLikKCiAgaWYgKGxlbmd0aChmYWNldF92YXJzKSAhPSAwKSB7CiAgICBwIDwtIHAgKyBmYWNldF93cmFwKGZhY2V0X3ZhcnMpCiAgfQogIHAKCn0KCmBgYAoKRnVuY3Rpb24gZm9yIGNhbGN1bGF0aW5nICBtZWFzdXJlcyBvZiBjaGFuZ2Ugb3ZlciB0aW1lIChSUi5wZWFrLCBSUi5sZXZlbCwgUlIuc2xvcGUpCgoKYGBge3J9CgpzdW1tYXJpc2VfY2hhbmdlIDwtIGZ1bmN0aW9uKG1vZGVsX2RhdGEsIG1vZGVsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yLCBncm91cGluZ192YXIgPSBOVUxMLCByZV9mb3JtdWxhID0gTlVMTCkgewogIAogICNmdW5jdGlvbnMgZm9yIGNhbGN1bGF0aW5nIFJSLnBlYWsKICAjaS5lLiByZWxhdGl2ZSBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIGluIDE5NTcgdnMuIGNvdW50ZXJmYWN0dWFsIHRyZW5kIGZvciAxOTU3CiAgCiAgZ3JvdXBpbmdfdmFyIDwtIGVucXVvKGdyb3VwaW5nX3ZhcikKICAKICBpZiAoIWlzLm51bGwoe3tncm91cGluZ192YXJ9fSkpIHsKICAgIAogICAgI21ha2UgdGhlIHByZWRpY3Rpb24gbWF0cml4LCBjb25kaXRpb25hbCBvbiB3aGV0aGVyIHdlIHdhbnQgcmFuZG9tIGVmZmVjdHMgaW5jbHVkZWQgb3Igbm90LgogICAgb3V0IDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0sICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSA9PSA4KSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJiLiBhY2YiKQogICAgKQogIH0gZWxzZSB7CiAgICAKICAgIG91dCA8LSBjcm9zc2luZyh7e21vZGVsX2RhdGF9fSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Qoe3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHlfbnVtKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSA9PSA4KSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJiLiBhY2YiKQogICAgKQogIH0KICAKICBwZWFrX2RyYXdzIDwtIGFkZF9lcHJlZF9kcmF3cyhuZXdkYXRhID0gb3V0LAogICAgICAgICAgICAgICAgICBvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICBtdXRhdGUoZXByZWRfY25yID0gLmVwcmVkL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICAgIGdyb3VwX2J5KC5kcmF3LCAhIWdyb3VwaW5nX3ZhcikgJT4lCiAgICBzdW1tYXJpc2UoZXN0aW1hdGUgPSBsYXN0KGVwcmVkX2NucikvZmlyc3QoZXByZWRfY25yKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5wZWFrIikKICAKICBwZWFrX3N1bW1hcnkgPC0gcGVha19kcmF3cyAlPiUKICAgIGdyb3VwX2J5KCEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgIG1lYW5fcWkoZXN0aW1hdGUpICU+JQogICAgbXV0YXRlKG1lYXN1cmUgPSAiUlIucGVhayIpCiAgCiAgCiAgI2Z1bmN0aW9ucyBmb3IgY2FsY3VsYXRpbmcgUlIubGV2ZWwKICAjaS5lLiByZWxhdGl2ZSBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIGluIDE5NTggdnMuIGNvdW50ZXJmYWN0dWFsIHRyZW5kIGZvciAxOTU4CiAgCiAgICBpZiAoIWlzLm51bGwoe3tncm91cGluZ192YXJ9fSkpIHsKICAgIG91dDIgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDkpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikKICAgICkKICB9IGVsc2UgewogICAgCiAgICBvdXQyIDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0pICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDkpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikKICAgICkKICB9CiAgCiAgICBsZXZlbF9kcmF3cyA8LSBhZGRfZXByZWRfZHJhd3MobmV3ZGF0YSA9IG91dDIsCiAgICAgICAgICAgICAgICAgIG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IHt7cmVfZm9ybXVsYX19KSAlPiUKICAgIGFycmFuZ2UoeV9udW0sIC5kcmF3KSAlPiUKICAgIG11dGF0ZShlcHJlZF9jbnIgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3QoZXByZWRfY25yKS9maXJzdChlcHJlZF9jbnIpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLmxldmVsIikKICAKICBsZXZlbF9zdW1tYXJ5IDwtIGxldmVsX2RyYXdzICU+JQogICAgZ3JvdXBfYnkoISFncm91cGluZ192YXIpICU+JQogICAgbWVhbl9xaShlc3RpbWF0ZSkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5sZXZlbCIpCiAgICAKICAgIAogICNmdW5jdGlvbnMgZm9yIGNhbGN1bGF0aW5nIFJSLnNsb3BlCiAgI2kuZS4gcmVsYXRpdmUgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgaW4gMTk1OC0xOTYzIHZzLiBjb3VudGVyZmFjdHVhbCB0cmVuZCBmb3IgMTk1OS0xOTYzCiAgCiAgICBpZiAoIWlzLm51bGwoe3tncm91cGluZ192YXJ9fSkpIHsKICAgIG91dDMgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtICVpbiUgYyg5LDE0KSksCiAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYy4gcG9zdC1hY2YiKQogICAgKQogIH0gZWxzZSB7CiAgICAKICAgIG91dDMgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoeV9udW0gJWluJSBjKDksMTQpKSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJjLiBwb3N0LWFjZiIpCiAgICApCiAgfQogIAogICAgc2xvcGVfZHJhd3MgPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXQzLAogICAgICAgICAgICAgICAgICBvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgICAgYXJyYW5nZSh5X251bSkgJT4lCiAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgIG11dGF0ZShlcHJlZF9jbnIgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogICAgICAgIGdyb3VwX2J5KC5kcmF3LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgIHN1bW1hcmlzZShzbG9wZSA9IGxhc3QoZXByZWRfY25yKS9maXJzdChlcHJlZF9jbnIpKSAlPiUKICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgZ3JvdXBfYnkoLmRyYXcsICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgICBzdW1tYXJpc2UoZXN0aW1hdGUgPSBsYXN0KHNsb3BlKS9maXJzdChzbG9wZSkpICU+JQogICAgICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnNsb3BlIikKICAKICBzbG9wZV9zdW1tYXJ5IDwtIHNsb3BlX2RyYXdzICU+JQogICAgIGdyb3VwX2J5KCEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgbWVhbl9xaShlc3RpbWF0ZSkgJT4lCiAgICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnNsb3BlIikKICAgIAogICNnYXRoZXIgYWxsIHRoZSByZXN1bHRzIGludG8gYSBuYW1lZCBsaXN0CiAgICBsc3QocGVha19kcmF3cz1wZWFrX2RyYXdzLCBwZWFrX3N1bW1hcnk9cGVha19zdW1tYXJ5LCAKICAgICAgICBsZXZlbF9kcmF3cz1sZXZlbF9kcmF3cywgbGV2ZWxfc3VtbWFyeT1sZXZlbF9zdW1tYXJ5LCAKICAgICAgICBzbG9wZV9kcmF3cz1zbG9wZV9kcmF3cywgc2xvcGVfc3VtbWFyeT1zbG9wZV9zdW1tYXJ5KQogIAp9CgpgYGAKCgpGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgZGlmZmVyZW5jZSBmcm9tIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCmNhbGN1bGF0ZV9jb3VudGVyZmFjdHVhbCA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwsIHJlX2Zvcm11bGE9TkEpewogIAogICNlZmZlY3QgdnMuIGNvdW50ZXJmYWN0dWFsCiAgY291bnRlcmZhY3QgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIiksCiAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0ge3tyZV9mb3JtdWxhfX0pICU+JQogICAgICBncm91cF9ieSguZHJhdywgeWVhciwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkgJT4lCiAgICAgIG11dGF0ZSguZXByZWRfaW5jX2NvdW50ZXJmID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwgLmVwcmVkX2NvdW50ZXJmPS5lcHJlZCkgICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoeWVhciwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIC5kcmF3LCAuZXByZWRfY291bnRlcmYsIC5lcHJlZF9pbmNfY291bnRlcmYsIHt7Z3JvdXBpbmdfdmFyfX0pCiAgCiAgI0NhbGN1YXRlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIHBvc3RfY2hhbmdlIDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0ge3ttb2RlbF9kYXRhfX0gJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kKSwKICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kKSAlPiUKICAgICAgbXV0YXRlKC5lcHJlZF9pbmMgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwKSAgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgLmRyYXcsIC5lcHJlZCwgLmVwcmVkX2luYywge3tncm91cGluZ192YXJ9fSkgCiAgCiAgI2ZvciB0aGUgb3ZlcmFsbCBwZXJpb2QKICAgIGNvdW50ZXJmYWN0X292ZXJhbGwgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIiksCiAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0ge3tyZV9mb3JtdWxhfX0pICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgLmRyYXcsIC5lcHJlZCwge3tncm91cGluZ192YXJ9fSkgICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWRfY291bnRlcmYgPSBzdW0oLmVwcmVkKSkgCiAgCiAgI0NhbGN1YXRlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIHBvc3RfY2hhbmdlX292ZXJhbGwgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpLAogICAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IHt7cmVfZm9ybXVsYX19KSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3Qoe3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIC5kcmF3LCAuZXByZWQpICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWQgPSBzdW0oLmVwcmVkKSkgCiAgCiAgCmNvdW50ZXJfcG9zdCA8LQogIGxlZnRfam9pbihjb3VudGVyZmFjdCwgcG9zdF9jaGFuZ2UpICU+JQogICAgbXV0YXRlKGNhc2VzX2F2ZXJ0ZWQgPSAuZXByZWRfY291bnRlcmYtLmVwcmVkLAogICAgICAgICAgIHBjdF9jaGFuZ2UgPSAoLmVwcmVkIC0gLmVwcmVkX2NvdW50ZXJmKS8uZXByZWRfY291bnRlcmYsCiAgICAgICAgICAgZGlmZl9pbmMxMDBrID0gLmVwcmVkX2luYyAtIC5lcHJlZF9pbmNfY291bnRlcmYsCiAgICAgICAgICAgcnJfaW5jMTAwayA9IC5lcHJlZF9pbmMvLmVwcmVkX2luY19jb3VudGVyZikgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSwgZGlmZl9pbmMxMDBrLCBycl9pbmMxMDBrKSAlPiUKICAgIHVuZ3JvdXAoKQoKY291bnRlcl9wb3N0X292ZXJhbGwgPC0KICBsZWZ0X2pvaW4oY291bnRlcmZhY3Rfb3ZlcmFsbCwgcG9zdF9jaGFuZ2Vfb3ZlcmFsbCkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZikgJT4lCiAgICBncm91cF9ieSh7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSkgJT4lCiAgICB1bmdyb3VwKCkKCmxzdChjb3VudGVyX3Bvc3QsIGNvdW50ZXJfcG9zdF9vdmVyYWxsKQoKfQoKCmBgYAoKRnVuY3Rpb24gZm9yIHRpZHlpbmcgdXAgY291bnRlcmZhY3R1YWxzIChtb3N0bHkgZm9yIG1ha2luZyBuaWNlIHRhYmxlcykKCmBgYHtyfQoKdGlkeV9jb3VudGVyZmFjdHVhbHMgPC0gZnVuY3Rpb24oZGF0YSl7CiAgZGF0YSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyLCBkaWZmX2luYzEwMGs6ZGlmZl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHJyX2luYzEwMGs6cnJfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSwKICAgICAgICAgICAgY2FzZXNfYXZlcnRlZCA9IGdsdWU6OmdsdWUoIntjYXNlc19hdmVydGVkfSAoe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfSAoe3BjdF9jaGFuZ2UubG93ZXJ9IHRvIHtwY3RfY2hhbmdlLnVwcGVyfSkiKSwKICAgICAgICAgICAgZGlmZl9pbmMgPSBnbHVlOjpnbHVlKCJ7ZGlmZl9pbmMxMDBrfSAoe2RpZmZfaW5jMTAway5sb3dlcn0gdG8ge2RpZmZfaW5jMTAway51cHBlcn0pIiksCiAgICAgICAgICAgIHJyX2luYyA9IGdsdWU6OmdsdWUoIntycl9pbmMxMDBrfSAoe3JyX2luYzEwMGsubG93ZXJ9IHRvIHtycl9pbmMxMDBrLnVwcGVyfSkiKSkKfQoKCnRpZHlfY291bnRlcmZhY3R1YWxzX292ZXJhbGwgPC0gZnVuY3Rpb24oZGF0YSl7CiAgZGF0YSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZSh5ZWFyID0gYXMuY2hhcmFjdGVyKHllYXIpLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9ICh7Y2FzZXNfYXZlcnRlZC5sb3dlcn0gdG8ge2Nhc2VzX2F2ZXJ0ZWQudXBwZXJ9KSIpLAogICAgICAgICAgICBwY3RfY2hhbmdlID0gZ2x1ZTo6Z2x1ZSgie3BjdF9jaGFuZ2V9ICh7cGN0X2NoYW5nZS5sb3dlcn0gdG8ge3BjdF9jaGFuZ2UudXBwZXJ9KSIpKQp9CgpgYGAKCgoKIyMjIDIuIERhdGEKCkltcG9ydCBkYXRhc2V0cyBmb3IgYW5hbHlzaXMKCiMjIyMgMi4xIFNoYXBlZmlsZXMKCk1ha2UgYSBtYXAgb2YgR2xhc2dvdyB3YXJkcwoKYGBge3J9CgpnbGFzZ293X3dhcmRzXzE5NTEgPC0gc3RfcmVhZChoZXJlKCJtYXBwaW5nL2dsYXNnb3dfd2FyZHNfMTk1MS5nZW9qc29uIikpCgpgYGAKCmBgYHtyfQoKI3JlYWQgaW4gU2NvdGxhbmQgYm91bmRhcnkKc2NvdGxhbmQgPC0gc3RfcmVhZChoZXJlKCJtYXBwaW5nL1Njb3RsYW5kX2JvdW5kYXJ5L1Njb3RsYW5kIGJvdW5kYXJ5LnNocCIpKQoKI21ha2UgYSBib3VuZGluZyBib3ggZm9yIEdsYXNnb3cKYmJveCA8LSBzdF9iYm94KGdsYXNnb3dfd2FyZHNfMTk1MSkgfD4gc3RfYXNfc2ZjKCkKCiNwbG90IHNjb3RsYW5kIHdpdGggYSBib3VuZGluZyBib3ggYXJvdW5kIHRoZSBDaXR5IG9mIEdsYXNnb3cKc2NvdGxhbmRfd2l0aF9iYm94IDwtIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSBzY290bGFuZCwgZmlsbD0iYW50aXF1ZXdoaXRlIikgKwogIGdlb21fc2YoZGF0YSA9IGJib3gsIGNvbG91ciA9ICIjQzYwQzMwIiwgZmlsbD0iYW50aXF1ZXdoaXRlIikgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BLCBsaW5ld2lkdGggPSAwLjUpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRUFGN0ZBIiwgc2l6ZSA9IDAuMykpCgojcGxvdCB0aGUgd2FyZHMKI25vdGUgd2UgdGlkeSB1cCBzb21lIG5hbWVzIHRvIGZpdCBvbiBtYXAKZ2xhc2dvd193YXJkX21hcCA8LSBnbGFzZ293X3dhcmRzXzE5NTEgJT4lCiAgbXV0YXRlKHdhcmQgPSBjYXNlX3doZW4od2FyZD09IlNoZXR0bGVzdG9uIGFuZCBUb2xsY3Jvc3MiIH4gIlNoZXR0bGVzdG9uIGFuZFxuVG9sbGNyb3NzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iUGFydGljayAoV2VzdCkiIH4gIlBhcnRpY2tcbihXZXN0KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09IlBhcnRpY2sgKEVhc3QpIiB+ICJQYXJ0aWNrXG4oRWFzdCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJOb3J0aCBLZWx2aW4iIH4gIk5vcnRoXG5LZWx2aW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJLaW5uaW5nIFBhcmsiIH4gIktpbm5pbmdcblBhcmsiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiB3YXJkKSkgJT4lCiAgCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGw9ZGl2aXNpb24pKSArCiAgZ2VvbV9zZl9sYWJlbChhZXMobGFiZWwgPSB3YXJkKSwgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5zaXplID0gTkEsIGNvbG91cj0iYmxhY2siKSArCiAgI3NjYWxlX2NvbG91cl9pZGVudGl0eSgpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJDaXR5IG9mIEdsYXNnb3cgRGl2aXNpb24iKSArCiAgdGhlbWVfZ3JleSgpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSIiLAogICAgICAgZmlsbD0iRGl2aXNpb24iKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BLCBsaW5ld2lkdGggPSAwLjUpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhbnRpcXVld2hpdGUiLCBzaXplID0gMC4zKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXk3OCIpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41LCB0aXRsZS50aGVtZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpKQoKI2FkZCB0aGUgbWFwIG9mIHNjb3RsYW5kIGFzIGFuIGluc2V0CmdsYXNnb3dfd2FyZF9tYXAgKyBpbnNldF9lbGVtZW50KHNjb3RsYW5kX3dpdGhfYmJveCwgMC43NSwgMCwgMSwgMC40KQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczEucG5nIiksIGhlaWdodD0xMCwgd2lkdGggPSAxMikKCgpgYGAKCkNhbGN1bGF0ZSBhcmVhcyBwZXIgZ2VvZ3JhcGhpY2FsIHVuaXQKCmBgYHtyfQpzZl91c2VfczIoRkFMU0UpICNodHRwczovL2dpdGh1Yi5jb20vci1zcGF0aWFsL3NmL2lzc3Vlcy8xNzYyCgpnbGFzZ293X3dhcmRzXzE5NTEgPC0gZ2xhc2dvd193YXJkc18xOTUxICU+JQogIG11dGF0ZShhcmVhID0gc3RfYXJlYShnbGFzZ293X3dhcmRzXzE5NTEpKQoKCmdsYXNnb3dfd2FyZHNfMTk1MSRhcmVhX2ttIDwtIHVuaXRzOjpzZXRfdW5pdHMoZ2xhc2dvd193YXJkc18xOTUxJGFyZWEsIGttXjIpCgoKYGBgCgoKTWFrZSBkaXZpc2lvbiBzaGFwZSBmaWxlcywgYW5kIGNhbGN1bGF0ZSBhcmVhCihzdG9wcGVkIHdvcmtpbmcsIG5lZWQgdG8gZml4ISkKCmBgYHtyfQoKIyBnbGFzZ293X2RpdmlzaW9uc18xOTUxIDwtIGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKIyAgIGdyb3VwX2J5KGRpdmlzaW9uKSAlPiUgCiMgICBzdW1tYXJpemUoZ2VvbWV0cnkgPSBzdF91bmlvbihnZW9tZXRyeSkpICU+JQojICAgbm5nZW86OnN0X3JlbW92ZV9ob2xlcygpICU+JQojICAgbXV0YXRlKGFyZWEgPSBzdF9hcmVhKGdsYXNnb3dfZGl2aXNpb25zXzE5NTEpKQojIAojIGdsYXNnb3dfZGl2aXNpb25zXzE5NTEkYXJlYV9rbSA8LSB1bml0czo6c2V0X3VuaXRzKGdsYXNnb3dfZGl2aXNpb25zXzE5NTEkYXJlYSwga21eMikKCgpgYGAKCgojIyMgMy4gRGVub21pbmF0b3JzCgpMb2FkIGluIHRoZSBkYXRhc2V0cyBmb3IgZGVub25vbWlhdG9ycywgYW5kIGNoZWNrIGZvciBjb25zaXN0ZW5jeS4KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzIDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gIm92ZXJhbGxfcG9wdWxhdGlvbiIpCgpvdmVyYWxsX3BvcHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKb3ZlcmFsbF9wb3BzIDwtIG92ZXJhbGxfcG9wcyAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCmBgYAoKTm90ZSwgd2UgaGF2ZSB0aHJlZSBwb3B1bGF0aW9uIGVzdGltYXRlczoKCjEuIFBvcHVsYXRpb24gd2l0aG91dCBpbnN0aXR1dGlvbmFsaXNlZCBwZW9wbGUgb3IgcGVvcGxlIGluIHNoaXBwaW5nCjIuIFBvcHVsYXRpb24gaW4gaW5zdGl0dXRpb25zCjMuIFBvcHVsYXRpb24gaW4gc2hpcHBpbmcKCihQb3B1bGF0aW9uIGluIHNoaXBwaW5nIGlzIGVzdGltYXRlZCBmcm9tIHRoZSAxOTUxIGNlbnN1cywgc28gaXMgdGhlIHNhbWUgZm9yIG1vc3QgeWVhcnMpCgojIyMjIDMuMSBPdmVyYWxsIHBvcHVsYXRpb24KCkZpcnN0LCBwbG90IHRoZSB0b3RhbCBwb3B1bGF0aW9uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIpLCBhbHBoYT0wLjUsIGNvbG91ciA9ICJtZWRpdW1zZWFncmVlbiIsIGZpbGw9Im1lZGl1bXNlYWdyZWVuIikgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiksIGNvbG91ciA9ICJtZWRpdW1zZWFncmVlbiIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogdG90YWwgcG9wdWxhdGlvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkKCgpgYGAKCk5vdyB0aGUgcG9wdWxhdGlvbiBleGNsdWRpbmcgaW5zdGl0dXRpb25hbGlzZWQgYW5kIHNoaXBwaW5nIHBvcHVsYXRpb24KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9cG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgeD15ZWFyMiksIGFscGhhPTAuNSwgY29sb3VyID0gInB1cnBsZSIsIGZpbGw9InB1cnBsZSIpICsKICBnZW9tX3BvaW50KGFlcyh5PXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHg9eWVhcjIpLCBjb2xvdXIgPSAicHVycGxlIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBwb3B1bGF0aW9uIGV4Y2x1ZGluZyBpbnN0aXR1dGlvbmFsaXNlZCBhbmQgc2hpcHBpbmciLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpCgoKYGBgCgojIyMjIDMuMiBQb3B1bGF0aW9uIGJ5IFdhcmQKClRoZXJlIGFyZSA1IERpdmlzaW9ucyBjb250YWluaW5nIDM3IFdhcmRzIGluIHRoZSBHbGFzZ293IENvcnBvcmF0aW9uLCB3aXRoIGNvbnNpc3RlbnQgYm91bmRhcmllcyBvdmVyIHRpbWUuCgpgYGB7cn0KI2xvb2stdXAgdGFibGUgZm9yIGRpdmlzaW9ucyBhbmQgd2FyZHMKd2FyZF9sb29rdXAgPC0gcmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAiZGl2aXNpb25zX3dhcmRzIikKCgp3YXJkX3BvcHMgPC0gcmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAid2FyZF9wb3B1bGF0aW9uIikKCndhcmRfcG9wcyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludAp3YXJkX3BvcHMgPC0gd2FyZF9wb3BzICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKI0dldCB0aGUgRGl2aXNpb24gcG9wdWxhdGlvbgpkaXZpc2lvbl9wb3BzIDwtIHdhcmRfcG9wcyAlPiUKICBncm91cF9ieShkaXZpc2lvbiwgeWVhcikgJT4lCiAgc3VtbWFyaXNlKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAgPSBzdW0ocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgaW5zdGl0dXRpb25zID0gc3VtKGluc3RpdHV0aW9ucywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgc2hpcHBpbmcgPSBzdW0oc2hpcHBpbmcsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHRvdGFsX3BvcHVsYXRpb24gPSBzdW0odG90YWxfcG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSkKCmRpdmlzaW9uX3BvcHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpQbG90IHRoZSBvdmVyYWxsIHBvcHVsYXRpb24gYnkgRGl2aXNpb24gYW5kIFdhcmQKCmBgYHtyfQoKZGl2aXNpb25fcG9wcyAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyLCBjb2xvdXI9ZGl2aXNpb24sIGZpbGw9ZGl2aXNpb24pLCBhbHBoYT0wLjgpICsKICBnZW9tX3BvaW50KGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbikpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIGZhY2V0X3dyYXAoZGl2aXNpb25+LikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIiwgbmFtZSA9ICIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IHRvdGFsIHBvcHVsYXRpb24gYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgpgYGAKCmBgYHtyfQoKd2FyZF9wb3BzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uLCBmaWxsPWRpdmlzaW9uKSkgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uKSwgY29sb3VyPSJibGFjayIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIGZhY2V0X3dyYXAod2FyZH4uLCBuY29sPTYpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJEaXZpc2lvbiIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiRGl2aXNpb24iKSArCiAgbGFicygKICAgIHggPSAiIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczIucG5nIiksIGhlaWdodD0xNCwgd2lkdGg9MTIpCgpgYGAKCkFwcHJveGltYXRlbHksIGhvdyBtYW55IHBlcnNvbi15ZWFycyBvZiBmb2xsb3ctdXAgZG8gd2UgaGF2ZT8KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKHllYXIsIGxlbmd0aCwgLm5hbWVzID0gInllYXJzIiksCiAgICAgICAgICAgIGFjcm9zcyhjKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pLCBzdW0pKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmRvdWJsZSksIGNvbW1hKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCkNoYW5nZSBpbiBwb3B1bGF0aW9uIGJ5IHdhcmQKCmBgYHtyfQoKd2FyZF9wb3BzICU+JQogIGdyb3VwX2J5KHdhcmQpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX3BvcCA9IChsYXN0KHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApIC0gZmlyc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpL2ZpcnN0KHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSAlPiUKICBtdXRhdGUocGN0X2NoYW5nZV9wb3AgPSBwZXJjZW50KHBjdF9jaGFuZ2VfcG9wKSkgJT4lCiAgYXJyYW5nZShwY3RfY2hhbmdlX3BvcCkgJT4lCiAgZGF0YXRhYmxlKCkKICAKCgpgYGAKCk91dHB1dCBwb3B1bGF0aW9uIGRlbnNpdHkgYnkgd2FyZCBhbmQgZGl2aXNvbiBmb3IgcmVncmVzc2lvbiBtb2RlbGxpbmcKCldhcmRzIGZpcnN0Cgooc3RvcHBlZCB3b3JraW5nLCBuZWVkIHRvIGZpeCkKCmBgYHtyfQoKIyB3YXJkX2NvdmFyaWF0ZXMgPC0gIGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKIyAgIGxlZnRfam9pbih3YXJkX3BvcHMpICU+JQojICAgbXV0YXRlKHBlb3BsZV9wZXJfa21fc3EgPSBhcy5kb3VibGUocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcC9hcmVhX2ttKSkKIyAKIyAjcGxvdCBpdCBvdXQKIyAKIyB3YXJkX2NvdmFyaWF0ZXMgJT4lCiMgICBnZ3Bsb3QoKSArCiMgICBnZW9tX3NmKGFlcyhmaWxsPXBlb3BsZV9wZXJfa21fc3EpKSArIAojICAgZmFjZXRfd3JhcCh5ZWFyfi4sIG5jb2w9NykgKwojICAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uPSJBIikgKwojICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiMgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkKIyAKIyBnZ3NhdmUoaGVyZSgiZmlndXJlcy93YXJkX3BvcF9kZW5zaXR5LnBuZyIpLCB3aWR0aD0xMCkKIyAKIyB3cml0ZV9yZHMod2FyZF9jb3ZhcmlhdGVzLCBoZXJlKCJwb3B1bGF0aW9ucy93YXJkX2NvdmFyaWF0ZXMucmRzIikpCgoKYGBgCgpOb3cgZGl2aXNpb25zIGZpcnN0CgoKKHN0b3BwZWQgd29ya2luZywgbmVlZCB0byBmaXgpCgpgYGB7cn0KCiMgZGl2aXNpb25fY292YXJpYXRlcyA8LSAgZ2xhc2dvd19kaXZpc2lvbnNfMTk1MSAlPiUKIyAgIGxlZnRfam9pbihkaXZpc2lvbl9wb3BzKSAlPiUKIyAgIG11dGF0ZShwZW9wbGVfcGVyX2ttX3NxID0gYXMuZG91YmxlKHRvdGFsX3BvcHVsYXRpb24vYXJlYV9rbSkpCiMgCiMgI3Bsb3QgaXQgb3V0CiMgCiMgZGl2aXNpb25fY292YXJpYXRlcyAlPiUKIyAgIGdncGxvdCgpICsKIyAgIGdlb21fc2YoYWVzKGZpbGw9cGVvcGxlX3Blcl9rbV9zcSkpICsgCiMgICBnZW9tX3NmX2xhYmVsKGFlcyhsYWJlbCA9IGRpdmlzaW9uKSwgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5zaXplID0gTkEsIGNvbG91cj0iYmxhY2siLCBmYW1pbHkgPSAiU2Vnb2UgVUkiKSArCiMgICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbD03KSArCiMgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249IkciKSArCiMgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKIyAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQojIAojIGdnc2F2ZShoZXJlKCJmaWd1cmVzL2RpdmlzaW9uX3BvcF9kZW5zaXR5LnBuZyIpLCB3aWR0aD0xMCkKIyAKIyB3cml0ZV9yZHMoZGl2aXNpb25fY292YXJpYXRlcywgaGVyZSgicG9wdWxhdGlvbnMvZGl2aXNpb25fY292YXJpYXRlcy5yZHMiKSkKCmBgYAoKCiMjIyMgMy4zIFBvcHVsYXRpb24gYnkgYWdlIGFuZCBzZXgKCmBgYHtyfQoKYWdlX3NleCA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJhZ2Vfc2V4X3BvcHVsYXRpb24iKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMobWFsZSwgZmVtYWxlKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAic2V4IikKCiNjb2xsYXBzZSBkb3duIHRvIHNtYWxsZXIgYWdlIGdyb3VwcyB0byBiZSBtYW5hZ2VhYmxlCmFnZV9zZXggPC0gYWdlX3NleCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2UgPT0gIjAgdG8gNCIgfiAiMDAgdG8gMDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1IHRvIDkiIH4gIjA1IHRvIDE0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMTAgdG8gMTQiIH4gIjA1IHRvIDE0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMTUgdG8gMTkiIH4gIjE1IHRvIDI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMjAgdG8gMjQiIH4gIjE1IHRvIDI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMjUgdG8gMjkiIH4gIjI1IHRvIDM0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMzAgdG8gMzQiIH4gIjI1IHRvIDM0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMzUgdG8gMzkiIH4gIjM1IHRvIDQ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNDAgdG8gNDQiIH4gIjM1IHRvIDQ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNDUgdG8gNDkiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNTAgdG8gNTQiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNTUgdG8gNTkiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiNjAgJiB1cCIpKSAlPiUKICBncm91cF9ieSh5ZWFyLCBhZ2UsIHNleCkgJT4lCiAgbXV0YXRlKHZhbHVlID0gc3VtKHZhbHVlKSkgJT4lCiAgdW5ncm91cCgpCgoKCm1fYWdlX3NleCA8LSBsbSh2YWx1ZSB+IHNwbGluZXM6Om5zKHllYXIsIGtub3RzID0gMykqYWdlKnNleCwgZGF0YSA9IGFnZV9zZXgpCgpzdW1tYXJ5KG1fYWdlX3NleCkKCmFnZV9sZXZlbHMgPC0gYWdlX3NleCAlPiUgc2VsZWN0KGFnZSkgJT4lIGRpc3RpbmN0KCkgJT4lIHB1bGwoKSAKCmFnZV9zZXhfbmQgPC0gCiAgY3Jvc3NpbmcoCiAgICBhZ2U9YWdlX2xldmVscywKICAgIHNleD1jKCJtYWxlIiwgImZlbWFsZSIpLAogICAgeWVhciA9IDE5NTA6MTk2MwogICkKCnByZWRfcG9wcyA8LSBhZ2Vfc2V4X25kICU+JSBtb2RlbHI6OmFkZF9wcmVkaWN0aW9ucyhtX2FnZV9zZXgpCgpwcmVkX3BvcHMgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9cHJlZCwgY29sb3VyPWFnZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKHNleH4uKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hLCBsaW1pdHMgPSBjKDAsIDEyNTAwMCkpCgojSG93IHdlbGwgZG8gdGhleSBtYXRjaCB1cCB3aXRoIG91ciBvdmVyYWxsIHBvcHVsYXRpb25zPwpwcmVkX3BvcHMgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgc3VtbWFyaXNlKHN1bV9wcmVkX3BvcCA9IHN1bShwcmVkKSkgJT4lCiAgcmlnaHRfam9pbihvdmVyYWxsX3BvcHMpICU+JQogIHNlbGVjdCh5ZWFyLCBzdW1fcHJlZF9wb3AsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhzdW1fcHJlZF9wb3AsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT12YWx1ZSwgY29sb3VyPW5hbWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoODAwMDAwLCAxMjUwMDAwKSkKCnByZWRfcG9wcyAlPiUKICBncm91cF9ieSh5ZWFyLCBzZXgpICU+JQogIHN1bW1hcmlzZShzdW0gPSBzdW0ocHJlZCkpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIG11dGF0ZShzZXhfcmF0aW8gPSBmaXJzdChzdW0pL2xhc3Qoc3VtKSkKYGBgCgoKV2hhdCBwZXJjZW50YWdlIG9mIGFkdWx0cyAoMTUrIHBhcnRpY2lwYXRlZCBpbiB0aGUgaW50ZXJ2ZW50aW9uIGluIDE5NTcpPwoKYGBge3J9CgpwcmVkX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcih5ZWFyPT0xOTU3KSAlPiUKICBmaWx0ZXIoYWdlICE9ICIwMCB0byAwNCIsCiAgICAgICAgIGFnZSAhPSAiMDUgdG8gMTQiKSAlPiUKICBzdW1tYXJpc2UodG90YWxfcG9wID0gc3VtKHByZWQpKSAlPiUKICBtdXRhdGUoY3hyX3NjcmVlbmVkID0gNjIyMzQ5KSAlPiUKICBtdXRhdGUocGN0X3BvcF9jeHJfc2NyZWVuZWQgPSBwZXJjZW50KGN4cl9zY3JlZW5lZC90b3RhbF9wb3ApKQoKcHJlZF9wb3BzICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIoeWVhcj09MTk1NykgJT4lCiAgZmlsdGVyKGFnZSAhPSAiMDAgdG8gMDQiLAogICAgICAgICBhZ2UgIT0gIjA1IHRvIDE0IikgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX3BvcCA9IHN1bShwcmVkKSwgLmJ5PXNleCkgJT4lCiAgbXV0YXRlKGN4cl9zY3JlZW5lZCA9IGMoMzQwNDc0LCAyODE4NzUpKSAlPiUKICBtdXRhdGUocGN0X3BvcF9jeHJfc2NyZWVuZWQgPSBwZXJjZW50KGN4cl9zY3JlZW5lZC90b3RhbF9wb3ApKQoKCmBgYAoKClBvcHVsYXRpb24gcHlyYW1pZHMKCmBgYHtyfQoKbGFiZWxfYWJzIDwtIGZ1bmN0aW9uKHgpIHsKICBjb21tYShhYnMoeCkpCn0KCgpwcmVkX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIG11dGF0ZSh5ZWFyX3BvcCA9IHN1bShwcmVkKSwKICAgICAgICAgYWdlX3NleF9wY3QgPSBwZXJjZW50KHByZWQveWVhcl9wb3AsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0ibWFsZSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJmZW1hbGUiIH4gIkZlbWFsZSIpKSAlPiUKICBnZ3Bsb3QoCiAgICBhZXMoeCA9IGFnZSwgZmlsbCA9IHNleCwgCiAgICAgICAgeSA9IGlmZWxzZSh0ZXN0ID0gc2V4ID09ICJGZW1hbGUiLHllcyA9IC1wcmVkLCBubyA9IHByZWQpKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBhZ2Vfc2V4X3BjdCksCiAgICAgICAgICAgIHBvc2l0aW9uPSBwb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBjb2xvdXI9ImJsYWNrIiwgc2l6ZT0yLjUpICsKICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbD03KSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfYWJzKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0NEN0FDNSIsICJjYWRldGJsdWUzIiksIG5hbWU9IiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0ID0gMSwgdmp1c3Q9MC41KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgbGFicyh4PSIiLCB5PSIiKSAKCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMy5wbmciKSwgd2lkdGg9MTApCgoKYGBgCgpOb3QgcGVyZmVjdCwgYnV0IHJlc29uYWJseSBnb29kLiBCdXQgYWhoaGhoLi4uIHRoZSBhZ2UgZ3JvdXBzIGRvbid0IGFsaWduIHdpdGggdGhlIGNhc2Ugbm90aWZpY2F0aW9uIGFnZSBncm91cHMhIENvbWUgYmFjayB0byB0aGluayBhYm91dCB0aGlzIGxhdGVyLgoKCiMjIyA0LiBUdWJlcmN1bG9zaXMgY2FzZXMKCkltcG9ydCB0aGUgdHViZXJjdWxvc2lzIGNhc2VzIGRhdGFzZXQKCgojIyMjIDQuMSBPdmVyYWxsIG5vdGlmaWNhdGlvbnMKCk92ZXJhbGwsIGJ5IHllYXIuCgpgYGB7cn0KCmNhc2VzX2J5X3llYXIgPC0gcmVhZF94bHN4KCIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJieV95ZWFyIikKCmNhc2VzX2J5X3llYXIlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKY2FzZXNfYnlfeWVhciA8LSBjYXNlc19ieV95ZWFyICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKYGBgCgpQbG90IHRoZSBvdmVyYWxsIG51bWJlciBvZiBjYXNlIG5vdGlmaWVkIHBlciB5ZWFyLCBieSBwdWxtb25hcnkgYW5kIGV4dHJhIHB1bG1vbmFyeSBjbGFzc2lmaWNhdGlvbi4KCmBgYHtyfQoKY2FzZXNfYnlfeWVhciAlPiUKICBzZWxlY3QoLXRvdGFsX25vdGlmaWNhdGlvbnMsIC15ZWFyKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMocHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMsIGBub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnNgKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBjYXNlX3doZW4obmFtZSA9PSAicHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAibm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zIiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT12YWx1ZSwgeD15ZWFyMiwgZ3JvdXAgPSBuYW1lLCBmaWxsPW5hbWUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBub3RpZmljYXRpb25zIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCiAgCgpgYGAKCiMjIyMgNC4yIE5vdGlmaWNhdGlvbnMgYnkgRGl2aXNpb24KClJlYWQgaW4gdGhlIGRhdGFzZXRzIGFuZCBtZXJnZSB0b2dldGhlci4KCmBgYHtyfQoKI2xpc3QgYWxsIHRoZSBzaGVldHMKYWxsX3NoZWV0cyA8LSBleGNlbF9zaGVldHMoIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIpCgojZ2V0IHRoZSB3YXJkIHNoZWV0cwp3YXJkX3NoZWV0cyA8LSBlbmZyYW1lKGFsbF9zaGVldHMpICU+JQogIGZpbHRlcihncmVwbCgiYnlfd2FyZCIsIHZhbHVlKSkgJT4lCiAgcHVsbCh2YWx1ZSkKCgpjYXNlc19ieV93YXJkX3NleF95ZWFyIDwtIG1hcF9kZih3YXJkX3NoZWV0cywgfnJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAuKSkKCmNhc2VzX2J5X3dhcmRfc2V4X3llYXIgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpBZ2dyZWdhdGUgdG9nZXRoZXIgdG8gZ2V0IGNhc2VzIGJ5IGRpdmlzaW9uCgpgYGB7cn0KCmNhc2VzX2J5X2RpdmlzaW9uIDwtIGNhc2VzX2J5X3dhcmRfc2V4X3llYXIgJT4lCiAgbGVmdF9qb2luKHdhcmRfbG9va3VwKSAlPiUKICBncm91cF9ieShkaXZpc2lvbiwgeWVhciwgdGJfdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGNhc2VzID0gc3VtKGNhc2VzLCBuYS5ybSA9IFRSVUUpKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKY2FzZXNfYnlfZGl2aXNpb24gPC0gY2FzZXNfYnlfZGl2aXNpb24gJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIHVuZ3JvdXAoKQoKY2FzZXNfYnlfZGl2aXNpb24gICU+JQogIHNlbGVjdCgteWVhcjIpICU+JQogIHNlbGVjdCh5ZWFyLCBldmVyeXRoaW5nKCkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpjYXNlc19ieV9kaXZpc2lvbiAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9Y2FzZXMsIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4sIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgbm90aWZpY2F0aW9ucyBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIGNhc2VzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKYGBgCgojIyMjIDQuMyBOb3RpZmljYXRpb25zIGJ5IHdhcmQKCmBgYHtyfQoKCmNhc2VzX2J5X3dhcmQgPC0gY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBncm91cF9ieSh3YXJkLCB5ZWFyLCB0Yl90eXBlKSAlPiUKICBzdW1tYXJpc2UoY2FzZXMgPSBzdW0oY2FzZXMsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKQoKY2FzZXNfYnlfd2FyZCAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIHNlbGVjdCh5ZWFyLCBldmVyeXRoaW5nKCkpICU+JQogIGRhdGF0YWJsZSgpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV93YXJkIDwtIGNhc2VzX2J5X3dhcmQgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpjYXNlc19ieV93YXJkICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1jYXNlcywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjgpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMgYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIGNhc2VzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKYGBgCgojIyMjIDQuNCBOb3RpZmljYXRpb25zIGJ5IGFnZSBhbmQgc2V4CgpBcyB3ZSBkb24ndCBoYXZlIGRlbm9taW5hdG9ycywgd2Ugd2lsbCBqdXN0IG1vZGVsIHRoZSBjaGFuZ2UgaW4gY291bnRzLgoKYGBge3J9CgojbGlzdCBhbGwgdGhlIHNoZWV0cwphbGxfc2hlZXRzIDwtIGV4Y2VsX3NoZWV0cygiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IikKCiNnZXQgdGhlIHdhcmQgc2hlZXRzCmFnZV9zZXhfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJieV9hZ2Vfc2V4IiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCmNhc2VzX2J5X2FnZV9zZXggPC0gbWFwX2RmKGFnZV9zZXhfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKY2FzZXNfYnlfYWdlX3NleCAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgoKCgojIyMgNSBUQiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlcwoKIyMjIyA1LjEgT3ZlcmFsbCBUQiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlcwoKTm93IGNhbGN1bGF0ZSBjYXNlIG5vdGlmaWNhdGlvbiByYXRlcyBwZXIgMTAwLDAwMCBwb3B1bGF0aW9uCgpNZXJnZSB0aGUgbm90aWZpY2F0aW9uIGFuZCBwb3B1bGF0aW9uIGRlbm9taW5hdG9yIGRhdGFzZXRzIHRvZ2V0aGVyLgoKSGVyZSB3ZSBuZWVkIHRvIGluY2x1ZGUgdGhlIHdob2xlIHBvcHVsYXRpb24gKHdpdGggc2hpcHBpbmcgYW5kIGluc3RpdHV0aW9ucykgYXMgdGhleSBhcmUgaW5jbHVkZWQgaW4gdGhlIG5vdGlmaWNhdGlvbnMuCgpgYGB7cn0KCm92ZXJhbGxfaW5jIDwtIG92ZXJhbGxfcG9wcyAlPiUKICBsZWZ0X2pvaW4oY2FzZXNfYnlfeWVhcikKCm92ZXJhbGxfaW5jIDwtIG92ZXJhbGxfaW5jICU+JQogIG11dGF0ZShpbmNfcHVsbV8xMDBrID0gcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMvdG90YWxfcG9wdWxhdGlvbioxMDAwMDAsCiAgICAgICAgIGluY19lcF8xMDBrID0gYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2AvdG90YWxfcG9wdWxhdGlvbioxMDAwMDAsCiAgICAgICAgIGluY18xMDBrID0gdG90YWxfbm90aWZpY2F0aW9ucy90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCkKCm92ZXJhbGxfaW5jICU+JQogIHNlbGVjdCh5ZWFyLCBpbmNfMTAwaywgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGssIGluY19wdWxtXzEwMGssIGluY19lcF8xMDBrKSwKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKHJvdW5kKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKYGBge3J9CgpvdmVyYWxsX2luYyAlPiUKICBzZWxlY3QoeWVhcjIsIGluY19wdWxtXzEwMGssIGluY19lcF8xMDBrKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoaW5jX3B1bG1fMTAwaywgYGluY19lcF8xMDBrYCkpICU+JQogIG11dGF0ZShuYW1lID0gY2FzZV93aGVuKG5hbWUgPT0gImluY19wdWxtXzEwMGsiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAiaW5jX2VwXzEwMGsiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXZhbHVlLCB4PXllYXIyLCBncm91cCA9IG5hbWUsIGZpbGw9bmFtZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKYGBgCgpDaGFuZ2UgaW4gY2FzZSBub3RpZmljYXRpb24gcmF0ZXMgcHJlLWludGVydmVudGlvbgoKYGBge3J9CiNwcmUtQUNGCm92ZXJhbGxfaW5jICU+JQogIGZpbHRlcih5ZWFyICVpbiUgMTk1MDoxOTU2KSAlPiUKICBzdW1tYXJpc2UoY2hhbmdlID0gKCgobGFzdChpbmNfcHVsbV8xMDBrKS1maXJzdChpbmNfcHVsbV8xMDBrKSkvZmlyc3QoaW5jX3B1bG1fMTAwaykpLzcpKjEwMCkKCiNwb3N0LUFDRgpvdmVyYWxsX2luYyAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIDE5NTg6MTk2MykgJT4lCiAgc3VtbWFyaXNlKGNoYW5nZSA9ICgoKGxhc3QoaW5jX3B1bG1fMTAwayktZmlyc3QoaW5jX3B1bG1fMTAwaykpL2ZpcnN0KGluY19wdWxtXzEwMGspKS82KSoxMDApCgpgYGAKCgoKCiMjIyMgNS4yIFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIGJ5IERpdmlzaW9uCgpgYGB7cn0KCmRpdmlzaW9uX2luYyA8LSBkaXZpc2lvbl9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV9kaXZpc2lvbikKCgpkaXZpc2lvbl9pbmMgPC0gZGl2aXNpb25faW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKQoKZGl2aXNpb25faW5jICU+JQogIHNlbGVjdCh5ZWFyLCBkaXZpc2lvbiwgdGJfdHlwZSwgaW5jXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKYGBge3J9CgpkaXZpc2lvbl9pbmMgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWluY18xMDBrLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKYGBgCgojIyMjIDUuMiBUQiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlcyBieSBXYXJkCgpIZXJlIHdlIHdpbGwgZmlsdGVyIG91dCB0aGUgaW5zdGl0dXRpb25zIGFuZCBoYXJib3VyIGZyb20gdGhlIGRlbm9taW5hdG9ycywgYXMgd2UgZG9uJ3QgaGF2ZSByZWxpYWJsZSBwb3B1bGF0aW9uIGRlbm9taW5hdG9ycyBmb3IgdGhlbS4KCmBgYHtyfQoKd2FyZF9pbmMgPC0gd2FyZF9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV93YXJkKQoKCndhcmRfaW5jIDwtIHdhcmRfaW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKQoKd2FyZF9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIHdhcmQsIHRiX3R5cGUsIGluY18xMDBrKSAlPiUKICBtdXRhdGVfYXQoLnZhcnMgPSB2YXJzKGluY18xMDBrKSwKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKHJvdW5kKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgpgYGB7cn0KCndhcmRfaW5jICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1pbmNfMTAwaywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiSW5jaWRlbmNlIChwZXIgMTAwLDAwMCkiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKCmBgYAoKT24gYSBtYXAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQoKc3RfYXNfc2YobGVmdF9qb2luKHdhcmRfaW5jLCBnbGFzZ293X3dhcmRzXzE5NTEpKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWluY18xMDBrKSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sID0gNykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hbWU9IkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkEiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBndWlkZXMoZmlsbD1ndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSkKCgoKYGBgCgoKIyMjIDYuIFRCIE1vcnRhbGl0eQoKIyMjIyA2LjEgT3ZlcmFsbCBNb3J0YWxpdHkKCkltcG9ydCB0aGUgVEIgbW9ydGFsaXR5IGRhdGEuCgpGaXJzdCwgb3ZlcmFsbCBkZWF0aHMuIE5vdGUgdGhhdCBpbiB0aGUgb3JpZ2luYWwgcmVwb3J0cywgd2UgaGF2ZSBhIHB1bG1vbmFyeSBUQiBkZWF0aCByYXRlIHBlciBtaWxsaW9uIGZvciBhbGwgeWVhcnMsIGFuZCBudW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBkZWF0aHMgZm9yIGVhY2ggeWVhciBhcGFydCBmcm9tIDE5NTAuCgpgYGB7cn0KCiNnZXQgdGhlIG92ZXJhbGwgbW9ydGFsaXR5IHNoZWV0cwpkZWF0aHNfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJkZWF0aHMiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKb3ZlcmFsbF9kZWF0aHMgPC0gbWFwX2RmKGRlYXRoc19zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpvdmVyYWxsX2RlYXRocyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKCmBgYAoKUGxvdCB0aGUgcmF3IG51bWJlcnMgb2YgcHVsbW9uYXJ5IGRlYXRocwoKYGBge3J9CgpvdmVyYWxsX2RlYXRocyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wdWxtb25hcnlfZGVhdGhzKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiI0RFMEQ5MiIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjREUwRDkyIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBsYWJzKHk9IlB1bG1vbmFyeSBUQiBkZWF0aHMgcGVyIHllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHRpdGxlID0gIk51bWJlcnMgb2YgcHVsbW9uYXJ5IFRCIGRlYXRocyIsCiAgICAgICBzdWJ0aXRsZSA9ICJHbGFzZ293LCAxOTUwLTE5NjMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogbm8gZGF0YSBmb3IgMTk1MCIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCk5vdyB0aGUgaW5jaWRlbmNlIG9mIHB1bG1vbmFyeSBUQiBkZWF0aAoKYGBge3J9Cm92ZXJhbGxfZGVhdGhzICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXB1bG1vbmFyeV9kZWF0aF9yYXRlX3Blcl8xMDBrKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiIzRENkNGQSIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjNEQ2Q0ZBIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoeT0iQW5udWFsIGluY2lkZW5jZSBvZiBkZWF0aCAocGVyIDEwMCwwMDApIiwKICAgICAgIHggPSAiWWVhciIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczcucG5nIiksIHdpZHRoPTEwKQoKYGBgCgoKIyMjIDYuIFRhYmxlIDEKCk1ha2UgVGFibGUgMSBoZXJlLCBhbmQgc2F2ZSBmb3IgcHVibGljYXRpb24uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUgCiAgc2VsZWN0KHllYXIsIHRvdGFsX3BvcHVsYXRpb24pICU+JQogIGxlZnRfam9pbihvdmVyYWxsX2luYyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgCiAgICAgICAgICAgICAgICAgICAgIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zLCBpbmNfcHVsbV8xMDBrLAogICAgICAgICAgICAgICAgICAgICBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYCwgaW5jX2VwXzEwMGssCiAgICAgICAgICAgICAgICAgICAgIHRvdGFsX25vdGlmaWNhdGlvbnMsIGluY18xMDBrKSkgJT4lCiAgbGVmdF9qb2luKG92ZXJhbGxfZGVhdGhzICU+JQogICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLAogICAgICAgICAgICAgICAgICAgICBwdWxtb25hcnlfZGVhdGhzLCBwdWxtb25hcnlfZGVhdGhfcmF0ZV9wZXJfMTAwaykpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfnJvdW5kKC4sIGRpZ2l0cz0xKSkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgCgpgYGAKCgpQcmVwYXJlIHRoZSBkYXRhc2V0cyBmb3IgbW9kZWxsaW5nCgpgYGB7cn0KCm1kYXRhIDwtIHdhcmRfaW5jICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCgptZGF0YV9leHRyYXB1bG1vbmFyeSA8LSB3YXJkX2luYyAlPiUKICBmaWx0ZXIodGJfdHlwZT09Ik5vbi1QdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBncm91cF9ieSh3YXJkKSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKHllYXI8PTE5NjEpICNubyBkYXRhIGZvciAxOTYyIGFuZCAxOTYzCgoKI3NjYWZmb2xkIGZvciBvdmVyYWxsIHByZWRpY3Rpb25zCm92ZXJhbGxfc2NhZmZvbGQgPC0gbWRhdGEgJT4lCiAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB3YXJkLCBjYXNlcykgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QpICU+JQogICAgc3VtbWFyaXNlKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAgPSBzdW0ocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCksCiAgICAgICAgICAgICAgY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICAgIGxlZnRfam9pbihtZGF0YV9leHRyYXB1bG1vbmFyeSAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgICAgICAgICAgICBzdW1tYXJpc2UoY2FzZXNfZXh0cmFwdWxtb25hcnkgPSBzdW0oY2FzZXMpKSkgJT4lCiAgICBtdXRhdGUoaW5jXzEwMGtfZXh0cmFwdWxtb25hcnkgPSBjYXNlc19leHRyYXB1bG1vbmFyeS9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkKCmBgYAoKCiMjIyA3LiBQdWxtb25hcnkgVEIgbW9kZWwKCiMjIyMgNy4xIEZpdCB0aGUgbW9kZWwgYW5kIHByaW9ycwoKVGhpcyBtb2RlbHMgdGhlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgb3ZlciB0aW1lLCB3aXRoIGEgc3RlcCBjaGFuZ2UgZm9yIHRoZSBpbnRlcnZlbnRpb24sIGFuZCBzbG9wZSBjaGFuZ2UgYWZ0ZXIgdGhlIGludGVydmVudGlvbi4KCldvcmsgb24gdGhlIHByaW9ycyBhIGJpdC4gV2Ugd2lsbCBidWlsZCB1cCBmcm9tIGxlc3MgY29tcGxleCB0byBtb3JlIGNvbXBsZXguCgphKSBpbnRlcmNlcHQgb25seSwgdG8gcHJlZGljdCBjb3VudCBvZiBjYXNlcwoKYXQgdGhlIGludGVyY2VwdCwgd2UgZXhwZWN0IHNvbWV3aGVyZSBhcm91bmQgMjUwMC4gV2Ugd2lsbCBzZXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiB0byBib3RoIDAuNSBhbmQgMSB0byBjaGVjayB3aGF0IGl0IGxvb2tzIGxpa2UKCmBgYHtyfQojIAojIGMocHJpb3IobG9nbm9ybWFsKDcuNjAwOTAyLCAwLjUpKSwgI2xvZygyNTAwKSA9IDcuNjAwOTAyCiMgICBwcmlvcihsb2dub3JtYWwoNy42MDA5MDIsIDEpKSkgJT4lIAojICAgcGFyc2VfZGlzdCgpICU+JSAKIyAgIAojICAgZ2dwbG90KGFlcyh5ID0gcHJpb3IsIGRpc3QgPSAuZGlzdCwgYXJncyA9IC5hcmdzKSkgKwojICAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoLjUsIC45NSkpICsKIyAgIHNjYWxlX3lfZGlzY3JldGUoTlVMTCwgbGFiZWxzID0gc3RyX2MoImxvZ25vcm1hbChsb2coMjAwMCksICIsIGMoMC41LCAxKSwgIikiKSwKIyAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMSkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbihleHAoaXRhbGljKHApKGJldGFbMF0pKSkpICsKIyAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDE1MDAwKSkKIyAKIyAKIyBwcmlvcihnYW1tYSgxLCAwLjAxKSkgJT4lCiMgICBwYXJzZV9kaXN0KCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHk9cHJpb3IsIGRpc3QgPSAuZGlzdCwgYXJncyA9IC5hcmdzKSkgKwojICAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoMC41LCAwLjk1KSkKIyAKIyAjbm93IGZpdCB0byBhIG1vZGVsLCBhbmQgcGxvdCBzb21lIHByaW9yIHJlYWxpc2F0aW9ucwojIAojIG1fcHJpb3IxIDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3Iobm9ybWFsKGxvZygyMDAwKSwgMC41KSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IxLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gdGliYmxlKGludGVyY2VwdD0xKSkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9aW50ZXJjZXB0LCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWxzID0gY29tbWEpCgoKYGBgCgpOb3cgdHJ5IHRvIGFkZCBpbiBhIHRlcm0gZm9yIHRoZSBlZmZlY3Qgb2YgeV9udW0uIFdlIGFudGljcGF0ZSB0aGF0IHRoZSBudW1iZXIgb2YgY2FzZXMgd2lsbCBkZWNsaW5lIGJ5IGFib3V0IDEtNSUgcGVyIHllYXIuIEhvd2V2ZXIsIGFzIHdlIGFyZSBwcmV0dHkgdW5jZXJ0YWluIGFib3V0IHRoaXMsIHdlIHdpbGwganVzdCBlbmNvZGUgYSB3ZWFrbHkgcmVndWxhcmlzaW5nIHByaW9yIHRvIHJlc3RyaWN0IHRoZSB5ZWFyIHNpemUgdG8gc2Vuc2libGUgcmFuZ2VzLgoKYGBge3J9CiMgCiMgCiMgbV9wcmlvcjIgPC0gYnJtKAojICAgY2FzZXMgfiAwICsgSW50ZXJjZXB0ICsgeV9udW0sCiMgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAojICAgZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsCiMgICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiMgICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coMjAwMCksIDAuNSksIGNsYXNzID0gYiwgY29lZiA9IEludGVyY2VwdCkgKwojICAgICAgICAgICBwcmlvcihnYW1tYSgxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwojICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMSksIGNsYXNzID0gYiwgY29lZiA9IHlfbnVtKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IyLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKQoKYGBgCgpOb3cgd2Ugd2FudCB0byBhZGQgaW4gYSBwcmlvciBmb3IgdGhlIGVmZmVjdCBvZiB0aGUgYWNmX2ludGVydmVudGlvbi4gV2UgYW50aWNpcGF0ZSB0aGUgcGVhayB0byBiZSBhbnl3aGVyZSBiZXR3ZWVuIG5vIGVmZmVjdCwgYW5kIGEgdHJpcGxpbmcKCmBgYHtyfQojIAojIG1fcHJpb3IzIDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCArIHlfbnVtICsgYWNmX3BlcmlvZCwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3Iobm9ybWFsKGxvZygyMDAwKSwgMC41KSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiLCBjb2VmID0geV9udW0pICsKIyAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMDAxKSwgY2xhc3MgPSBiKQojICkKIyAKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IzLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVscyA9IGNvbW1hKQojIAoKCmBgYAoKTm93IHdlIGxvb2sgYW5kIHNlZSB3aGF0IGl0IGxvb2tzIGxpa2Ugd2l0aCB0aGUgaW50ZXJhY3Rpb25zCgpgYGB7cn0KIyAKIyBtX3ByaW9yNCA8LSBicm0oCiMgICBjYXNlcyB+IDAgKyBJbnRlcmNlcHQgKyB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kLAojICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKIyAgIGRhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLAojICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAojICAgcHJpb3IgPSBwcmlvcihub3JtYWwobG9nKDI1MDApLCAxKSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3I0LAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKQojIAojIAoKYGBgCgpOb3cgdHJ5IGFkZGluZyBpbiB0aGUgcmFuZG9tIGludGVyY2VwdHMKCmBgYHtyfQoKIyBjKHByaW9yKGxvZ25vcm1hbCgzLjkxMjAyMywgMC41KSksICNsb2coNTApID0gMy45MTIwMjMKIyAgIHByaW9yKGxvZ25vcm1hbCgzLjkxMjAyMywgMSkpKSAlPiUgCiMgICBwYXJzZV9kaXN0KCkgJT4lIAojICAgCiMgICBnZ3Bsb3QoYWVzKHkgPSBwcmlvciwgZGlzdCA9IC5kaXN0LCBhcmdzID0gLmFyZ3MpKSArCiMgICBzdGF0X2hhbGZleWUoLndpZHRoID0gYyguNSwgLjk1KSkgKwojICAgc2NhbGVfeV9kaXNjcmV0ZShOVUxMLCBsYWJlbHMgPSBzdHJfYygibG9nbm9ybWFsKGxvZyg1MCksICIsIGMoMC41LCAxKSwgIikiKSwKIyAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMSkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbihleHAoaXRhbGljKHApKGJldGFbMF0pKSkpICsKIyAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDQwMCkpCiMgCiMgCiMgbV9wcmlvcjUgPC0gYnJtKAojICAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kICsgKCAxIHwgd2FyZCksCiMgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAojICAgZGF0YSA9IG1kYXRhLAojICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAojICAgcHJpb3IgPSBwcmlvcihub3JtYWwobG9nKDUwKSwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKSArCiMgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkKIyApCiMgCiMgCiMgYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNSwKIyAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gTkEpICU+JQojICAgZ2dwbG90KGFlcyh4PXllYXIsIHk9LmVwcmVkKSkgKwojICAgc3RhdF9oYWxmZXllKCkgKwojICAgc2NhbGVfeV9sb2cxMChsYWJlbD1jb21tYSkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3I1LAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGEsCiMgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSBOQSkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKSArCiMgICBmYWNldF93cmFwKHdhcmR+LikKCmBgYAoKQW5kIGFkZCBpbiB0aGUgcmFuZG9tIHNsb3BlcwoKYGBge3J9CiMgCiMgbV9wcmlvcjYgPC0gYnJtKAojICAgY2FzZXMgfiAxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgeV9udW06YWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpLAojICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKIyAgIGRhdGEgPSBtZGF0YSwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3IoZ2FtbWEoMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKIyAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMSksIGNsYXNzID0gYikgKwojICAgICAgICAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3M9c2QpICsKIyAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz1jb3IpCiMgKQojIAojIAojIAojIG1fcHJpb3I2IDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCArIHlfbnVtICsgYWNmX3BlcmlvZCArIHlfbnVtOmFjZl9wZXJpb2QgKyAoIHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gbWRhdGEsCiMgICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiMgICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coNTApLCAxKSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKSArCiMgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEwMCksIGNsYXNzPXNkKSArCiMgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9Y29yKQojICkKCgojIGFkZF9lcHJlZF9kcmF3cyhvYmplY3Q9bV9wcmlvcjYsCiMgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YSwKIyAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IE5BKSAlPiUKIyAgIGdncGxvdChhZXMoeD15ZWFyLCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpCiMgCiMgYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNiwKIyAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gfiggMSArIHlfbnVtICsgYWNmX3BlcmlvZCB8IHdhcmQpKSAlPiUKIyAgIGdncGxvdChhZXMoeD15ZWFyLCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpICsKIyAgIGZhY2V0X3dyYXAod2FyZH4uKQojIAojIHBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsPW1fcHJpb3I2LCBvdXRjb21lID0gaW5jXzEwMGssIAojICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHJlX2Zvcm11bGEgPSBOQSkKIyAKIyBwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YSwgbW9kZWw9bV9wcmlvcjYsIG91dGNvbWUgPSBpbmNfMTAwaywgCiMgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCwKIyAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KCAxICsgeV9udW0gKyBhY2ZfcGVyaW9kIHwgd2FyZCkpCgpgYGAKCgpJc3N1ZSBoZXJlIGlzIHRoZSBub24tY2VudHJlZCBwYXJhbWV0ZXJpc2F0aW9uIG9mIHRoZSBpbnRlcmNlcHQgcHJpb3IuLi4gRmVlbCBsaWtlIHRoaXMgaXMgYSBtb3JlIGludGVycHJldGFibGUgd2F5IHRvIHNldCBwcmlvcnMuLi4gYnV0IHdpbGwgcmV2ZXJ0IHRvIGNlbnRyZWQgcGFyYW1ldGVyaXNhdGlvbiBmb3IgdGhlIG1lYW50aW1lLgoKCmBgYHtyfQojIG1fY2VudGVyZWRfcHJpb3IgPC0gYnJtKAojICAgY2FzZXMgfiAxICsgeV9udW0qYWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiMgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiMgICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LAojICAgICAgICAgICAgICAgICAgIHByaW9yID0gcHJpb3Iobm9ybWFsKDAsMTAwMCksIGNsYXNzID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjAxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwojICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpICsKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkgKwojICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz1jb3IpLAojICAgICAgICAgICAgICAgICAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IikKIyAKIyBwbG90KG1fY2VudGVyZWRfcHJpb3IpCiMgCiMgcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWw9bV9jZW50ZXJlZF9wcmlvciwgb3V0Y29tZSA9IGluY18xMDBrLCAKIyAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCByZV9mb3JtdWxhID0gTkEpCiMgCiMgcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEsIG1vZGVsPW1fY2VudGVyZWRfcHJpb3IsIG91dGNvbWUgPSBpbmNfMTAwaywgCiMgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCwKIyAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KCAxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpKQoKYGBgCgoKCgpMb29rIGF0IHRoZSBtZWFuIGFuZCB2YXJpYW5jZSBvZiBjb3VudHMgKGNvdW50cyBvZiBwdWxtb25hcnkgbm90aWZpY2F0aW9ucyBhcmUgd2hhdCB3ZSBhcmUgcHJlZGljdGluZykKCmBgYHtyfQoKI01lYW4gb2YgY291bnRzIHBlciB5ZWFyCm1lYW4obWRhdGEkY2FzZXMpCiN2YXJpYW5jZSBvZiBjb3VudHMgcGVyIHllYXIKdmFyKG1kYXRhJGNhc2VzKQoKYGBgCgoKCgoKUXVpdGUgYSBiaXQgb2Ygb3Zlci1kaXNwZXJzaW9uIGhlcmUsIHNvIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBtaWdodCBiZSBhIGJldHRlciBjaG9pY2Ugb2YgZGlzdHJpYnV0aW9uYWwgZmFtaWx5IHRoYW4gUG9pc3Nvbi4KCkZpdCB0aGUgbW9kZWwgd2l0aCB0aGUgZGF0YQoKYGBge3J9CgptX3B1bG1vbmFyeSA8LSBicm0oCiAgY2FzZXMgfiAxICsgeV9udW0qYWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YSwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwKICAgICAgICAgICAgICAgICAgcHJpb3IgPSBwcmlvcihub3JtYWwoMCwxKSwgY2xhc3MgPSBJbnRlcmNlcHQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjAxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IoZXhwb25lbnRpYWwoMSksIGNsYXNzPXNkKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDQpLCBjbGFzcz1jb3IpLAogIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45KSkKICAKI2NoZWNrIG1vZGVsIGRpYWdub3N0aWNzCnN1bW1hcnkobV9wdWxtb25hcnkpCnBsb3QobV9wdWxtb25hcnkpCgpwcF9jaGVjayhtX3B1bG1vbmFyeSwgdHlwZT0nZWNkZl9vdmVybGF5JykKcHJpb3Jfc3VtbWFyeShtX3B1bG1vbmFyeSkKCmBgYAoKTmljZXIgdmVyc2lvbiBvZiB0cmFjZSBwbG90cyBmb3Igc3VwcGxlbWVudGFsIG1hdGVyaWFsCgpgYGB7ciwgZmlnLmhlaWdodD0xNiwgZmlnLndpZHRoPTE2fQoKYXNfZHJhd3NfZGYobV9wdWxtb25hcnkpICU+JSAKICBiYXllc3Bsb3Q6Om1jbWNfcmFua19vdmVybGF5KHBhcnMgPSB2YXJzKGJfSW50ZXJjZXB0OnNoYXBlKSwKICAgICAgICAgICAgIGZhY2V0X2FyZ3MgPSBsaXN0KG5jb2wgPSA0KSkgKwogIHNjYWxlX2NvbG91cl9zY2ljb19kKHBhbGV0dGUgPSAibWFuYWd1YSIsIG5hbWUgPSAiQ2hhaW4iKSArCiAgdGhlbWVfZ2dkaXN0KCkrCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIikKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M1LnBuZyIpLCB3aWR0aD0xNiwgaGVpZ2h0PTE2KQpgYGAKCk5pY2VyIHZlcnNpb24gb2YgdGFibGUgb2YgcGFyYW1ldGVycyBmb3Igc3VwcGxlbWVudAoKYGBge3J9CgpzdW1tYXJpc2VfZHJhd3MobV9wdWxtb25hcnkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhtZWFuOmVzc190YWlsKSwgY29tbWEsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICB3cml0ZV9jc3YoaGVyZSgiZmlndXJlcy9zMV90YWJsZS5jc3YiKSkKCmBgYAoKCgojIyMjIDcuMiBTdW1tYXJpc2UgY2hhbmdlIGluIENOUnMKClN1bW1hcmlzZSB0aGUgcG9zdGVyaW9yIGluIGdyYXBoaWNhbCBmb3JtCgpgYGB7cn0KCmYxYiA8LSBwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLCBtb2RlbCA9IG1fcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIG91dGNvbWUgPSBpbmNfMTAwaywgZ3JvdXBpbmdfdmFyPU5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSBOQSkKICAKZjFiCmBgYAoKTWFrZSB0aGlzIGludG8gYSBmaWd1cmUgY29tYmluZWQgd2l0aCB0aGUgbWFwIG9mIGVtcGlyaWNhbCBkYXRhCgpgYGB7cn0KCmYxYSA8LSBzdF9hc19zZihsZWZ0X2pvaW4od2FyZF9pbmMsIGdsYXNnb3dfd2FyZHNfMTk1MSkpICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGw9aW5jXzEwMGspKSArCiAgZmFjZXRfd3JhcCh5ZWFyfi4sIG5jb2wgPSA3KSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobmFtZT0iQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCAiY20iKSwKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLjUsCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBzaXplPTYsIGhqdXN0PTEpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9NikpICsKICBndWlkZXMoZmlsbD1ndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSkKCihmMWEgLyBmMWIpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMS5wbmciKSwgd2lkdGg9NykKCmBgYAoKU3VtbWFyeSBvZiBjaGFuZ2UgaW4gbm90aWZpY2F0aW9ucyBudW1lcmljYWxseQoKYGBge3J9CgpvdmVyYWxsX2NoYW5nZSA8LSBzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGE9b3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWw9bV9wdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3I9cG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyPU5VTEwsIHJlX2Zvcm11bGEgPSBOQSkKCiN3YW50IHRvIGtlZXAgdGhlIHN1bW1hcnkgZXN0aW1hdGVzIGhlcmUKdG9rZWVwIDwtIGMoInBlYWtfc3VtbWFyeSIsICJsZXZlbF9zdW1tYXJ5IiwgInNsb3BlX3N1bW1hcnkiKQoKI3N1bW1hcnkgbWVhc3VyZXMgaW4gYSB0YWJsZQpvdmVyYWxsX2NoYW5nZSAlPiUKICBrZWVwKChuYW1lcyguKSAlaW4lIHRva2VlcCkpICU+JQogIGJpbmRfcm93cygpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKICAKYGBgCgoKIyMjIyA3LjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCk51bWJlcnMgb2YgcHVsbW9uYXJ5IFRCIGNhc2VzIGF2ZXJ0ZWQgY29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwgcGVyIHllYXIuCgpgYGB7cn0KCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmIDwtIGNhbGN1bGF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWw9bV9wdWxtb25hcnksIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpUb3RhbCBwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBiZXR3ZWVuIDE5NTggYW5kIDE5NjMKCmBgYHtyfQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKIyMjIyA3LjQgQ29ycmVsYXRpb24gYmV0d2VlbiBSUi5wZWFrLCBSUi5sZXZlbCwgYW5kIFJSLnNsb3BlCgpXaGF0IGFyZSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gcGVhaywgbGV2ZWwsIGFuZCBzbG9wZT8KCmBgYHtyfQoKI1JSLnBlYWsgaGlzdG9ncmFtCmEgPC0gb3ZlcmFsbF9jaGFuZ2UkcGVha19kcmF3cyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9ZXN0aW1hdGUpLCBmaWxsPSJkYXJrYmx1ZSIsIGNvbG91cj0iZGFya2JsdWUiLCBhbHBoYT0wLjMpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IlJSLnBlYWsiLAogICAgICAgeT0iIikKCiNSUi4gbGV2ZWwgaGlzdG9ncmFtCmIgPC0gb3ZlcmFsbF9jaGFuZ2UkbGV2ZWxfZHJhd3MgICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeD1lc3RpbWF0ZSksIGZpbGw9ImRhcmtibHVlIiwgY29sb3VyPSJkYXJrYmx1ZSIsIGFscGhhPTAuMykrCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGxhYnMoeD0iUlIubGV2ZWwiLAogICAgICAgeT0iIikKCiNSUi5zbG9wZSBoaXN0b2dyYW0KYyA8LSBvdmVyYWxsX2NoYW5nZSRzbG9wZV9kcmF3cyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9ZXN0aW1hdGUpLCBmaWxsPSJkYXJrYmx1ZSIsIGNvbG91cj0iZGFya2JsdWUiLCBhbHBoYT0wLjMpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsgIAogICNzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA2KSkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGxhYnMoeD0iUlIuc2xvcGUiLAogICAgICAgeT0iIikKCgojQ29ycmVsYXRpb24gYmV0d2VlbiBSUi5wZWFrIGFuZCBSUi5sZXZlbApjb3JfcnJfcGVha19ycl9sZXZlbCA8LSByb3VuZChjb3IocGx1Y2sob3ZlcmFsbF9jaGFuZ2UkcGVha19kcmF3cyRlc3RpbWF0ZSksIHBsdWNrKG92ZXJhbGxfY2hhbmdlJGxldmVsX2RyYXdzJGVzdGltYXRlKSksIGRpZ2l0cyA9IDIpCgojQ29ycmVsYXRpb24gYmV0d2VlbiBSUi5wZWFrIGFuZCBSUi5zbG9wZQpjb3JfcnJfcGVha19ycl9zbG9wZSA8LSByb3VuZChjb3IocGx1Y2sob3ZlcmFsbF9jaGFuZ2UkcGVha19kcmF3cyRlc3RpbWF0ZSksIHBsdWNrKG92ZXJhbGxfY2hhbmdlJHNsb3BlX2RyYXdzJGVzdGltYXRlKSksIGRpZ2l0cyA9IDIpCgojQ29ycmVsYXRpb24gYmV0d2VlbiBSUi5sZXZlbCBhbmQgUlIuc2xvcGUKY29yX3JyX2xldmVsX3JyX3Nsb3BlIDwtIHJvdW5kKGNvcihwbHVjayhvdmVyYWxsX2NoYW5nZSRsZXZlbF9kcmF3cyRlc3RpbWF0ZSksIHBsdWNrKG92ZXJhbGxfY2hhbmdlJHNsb3BlX2RyYXdzJGVzdGltYXRlKSksIGRpZ2l0cyA9IDIpCgoKI3Bsb3Qgb2YgY29ycmVsYXRpb24gYmV0d2VlbiBSUi5wZWFrIGFuZCBSUi5sZXZlbApkIDwtIGJpbmRfY29scyhSUi5wZWFrPXBsdWNrKG92ZXJhbGxfY2hhbmdlJHBlYWtfZHJhd3MkZXN0aW1hdGUpLCAKICAgICAgICAgIFJSLmxldmVsID1wbHVjayhvdmVyYWxsX2NoYW5nZSRsZXZlbF9kcmF3cyRlc3RpbWF0ZSkpICU+JQogIGdncGxvdChhZXMoeT1SUi5wZWFrLCB4ID0gUlIubGV2ZWwpKSArCiAgZ2VvbV9oZXgoKSArCiAgZ2VvbV9zbW9vdGgoc2U9RkFMU0UsIGNvbG91cj0iZmlyZWJyaWNrIiwgbWV0aG9kID0gImxtIikgKwogIGdlb21fdGV4dChhZXMoeT0yLjIsIHg9MC41OCwgbGFiZWw9Y29yX3JyX3BlYWtfcnJfbGV2ZWwpLCBjb2xvdXI9ImZpcmVicmljayIpICArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCiNwbG90IG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhayBhbmQgUlIuc2xvcGUKZSA8LSBiaW5kX2NvbHMoUlIucGVhaz1wbHVjayhvdmVyYWxsX2NoYW5nZSRwZWFrX2RyYXdzJGVzdGltYXRlKSwgCiAgICAgICAgICBSUi5zbG9wZSA9cGx1Y2sob3ZlcmFsbF9jaGFuZ2Ukc2xvcGVfZHJhd3MkZXN0aW1hdGUpKSAlPiUKICBnZ3Bsb3QoYWVzKHk9UlIucGVhaywgeCA9IFJSLnNsb3BlKSkgKwogIGdlb21faGV4KCkgKwogIGdlb21fc21vb3RoKHNlPUZBTFNFLCBjb2xvdXI9ImZpcmVicmljayIsIG1ldGhvZCA9ICJsbSIpICsKICBnZW9tX3RleHQoYWVzKHk9Mi4xLCB4PTAuNjUsIGxhYmVsPWNvcl9ycl9wZWFrX3JyX3Nsb3BlKSwgY29sb3VyPSJmaXJlYnJpY2siKSAgKwogICNzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA2KSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgojcGxvdCBvZiBjb3JyZWxhdGlvbiBiZXR3ZWVuIFJSLmxldmVsIGFuZCBSUi5zbG9wZQpmIDwtIGJpbmRfY29scyhSUi5sZXZlbD1wbHVjayhvdmVyYWxsX2NoYW5nZSRsZXZlbF9kcmF3cyRlc3RpbWF0ZSksIAogICAgICAgICAgUlIuc2xvcGUgPXBsdWNrKG92ZXJhbGxfY2hhbmdlJHNsb3BlX2RyYXdzJGVzdGltYXRlKSkgJT4lCiAgZ2dwbG90KGFlcyh5PVJSLmxldmVsLCB4ID0gUlIuc2xvcGUpKSArCiAgZ2VvbV9oZXgoKSArCiAgZ2VvbV9zbW9vdGgoc2U9RkFMU0UsIGNvbG91cj0iZmlyZWJyaWNrIiwgbWV0aG9kID0gImxtIikgKwogIGdlb21fdGV4dChhZXMoeT0wLjc1LCB4PTAuNjUsIGxhYmVsPWNvcl9ycl9sZXZlbF9ycl9zbG9wZSksIGNvbG91cj0iZmlyZWJyaWNrIikgICsgIAogICNzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA2KSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKKHBsb3Rfc3BhY2VyKCkgKyBwbG90X3NwYWNlcigpICsgYykgLwogIChwbG90X3NwYWNlcigpICsgYiArIGYpIC8KICAoYSArIGQgKyBlKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczYucG5nIiksIHdpZHRoPTgsIGhlaWdodD04KQoKCgpgYGAKCgojIyMjIDcuNSBXYXJkIGxldmVsIHB1bG1vbmFyeSBUQiBlc3RpbWF0ZXMKClBsb3QgdGhlIGNvdW50ZXJmYWN0dWFsIGF0IHdhcmQgbGV2ZWwKCmBgYHtyfQoKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEsIG1vZGVsPW1fcHVsbW9uYXJ5LCBvdXRjb21lID0gaW5jXzEwMGssIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCAKICAgICAgICAgICAgICAgICAgICBncm91cGluZ192YXIgPSB3YXJkLCB3YXJkLCByZV9mb3JtdWxhPSB+KDEgKyB5X251bSphY2ZfcGVyaW9kIHwgd2FyZCkpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M0LnBuZyIpLCB3aWR0aD0xMiwgaGVpZ2h0PTEyKQoKYGBgCgpTdW1tYXJ5IG9mIGNoYW5nZSBpbiBub3RpZmljYXRpb25zIGF0IHdhcmQgbGV2ZWwKCmBgYHtyfQoKd2FyZF9jaGFuZ2UgPC0gc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW1kYXRhLCBtb2RlbD1tX3B1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvcj1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXI9d2FyZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IH4oMSArIHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSkKCiN3YW50IHRvIGtlZXAgdGhlIHN1bW1hcnkgZXN0aW1hdGVzIGhlcmUKdG9rZWVwIDwtIGMoInBlYWtfc3VtbWFyeSIsICJsZXZlbF9zdW1tYXJ5IiwgInNsb3BlX3N1bW1hcnkiKQoKI3N1bW1hcnkgbWVhc3VyZXMgaW4gYSB0YWJsZQp3YXJkX2NoYW5nZSAlPiUKICBrZWVwKChuYW1lcyguKSAlaW4lIHRva2VlcCkpICU+JQogIGJpbmRfcm93cygpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKCiNwbG90IHRoZXNlIGluIGEgZmlndXJlCndhcmRfZWZmZWN0cyA8LSB3YXJkX2NoYW5nZSAlPiUKICBrZWVwKChuYW1lcyguKSAlaW4lIHRva2VlcCkpICU+JQogIGJpbmRfcm93cygpICU+JQogIGJpbmRfcm93cyhvdmVyYWxsX2NoYW5nZSRwZWFrX3N1bW1hcnkpICU+JQogIGJpbmRfcm93cyhvdmVyYWxsX2NoYW5nZSRsZXZlbF9zdW1tYXJ5KSAlPiUKICBiaW5kX3Jvd3Mob3ZlcmFsbF9jaGFuZ2Ukc2xvcGVfc3VtbWFyeSkgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhlc3RpbWF0ZToudXBwZXIpLCAKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKGFzLm51bWVyaWMpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBtdXRhdGUoZXN0aW1hdGUgPSBhcy5kb3VibGUoZXN0aW1hdGUpKSAlPiUKICBmdWxsX2pvaW4oZ2xhc2dvd193YXJkc18xOTUxKSAlPiUgCiAgbXV0YXRlKHdhcmQyID0gcGFzdGUwKHdhcmRfbnVtYmVyLCAiLiAiLCB3YXJkKSkgJT4lCiAgbXV0YXRlKHdhcmQyID0gY2FzZV93aGVuKGlzLm5hKHdhcmQpIH4gIk92ZXJhbGwiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiB3YXJkMikpICU+JQogIHN0X2FzX3NmKCkgCgojZnVuY3Rpb24gZm9yIHBsb3R0aW5nIGNob3JvcGxldGggbWFwcwpwbG90X3dhcmRfZWZmZWN0IDwtIGZ1bmN0aW9uKGRhdGEsIG1lYXN1cmUpewogIHt7ZGF0YX19ICU+JQogIGZpbHRlcihtZWFzdXJlID09IHt7bWVhc3VyZX19KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1lc3RpbWF0ZSkpICsKICBnZW9tX3NmX2xhYmVsKGFlcyhsYWJlbCA9IHdhcmRfbnVtYmVyKSwgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5zaXplID0gTkEsIGNvbG91cj0iYmxhY2siKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIiwgbmFtZT0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpICsKICAgIGxhYnMoeD0iIiwgeT0iIikKfQoKI2Z1bmN0aW9uIGZvciBwbG90dGluZyBjYXRhcGlsbGVyIHBsb3RzCnBsb3Rfd2FyZF9jYXQgPC0gZnVuY3Rpb24oZGF0YSwgbWVhc3VyZSwgc2NhbGUpewoKICBwYWwgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCdkYXJrYmx1ZScsJ2xpZ2h0Ymx1ZScpKQoKICB7e2RhdGF9fSAlPiUKICAgIGZpbHRlcihtZWFzdXJlPT17e21lYXN1cmV9fSkgJT4lCiAgICBtdXRhdGUobXlfcGFsZXR0ZSA9IGNhc2Vfd2hlbih3YXJkMj09Ik92ZXJhbGwiIH4gIiNDNjBDMzAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBwYWwoMzYpW2FzLm51bWVyaWMoY3V0KC4kZXN0aW1hdGUsYnJlYWtzID0gMzYpKV0pKSAlPiUKICAgIGdncGxvdCgpICsKICAgIGdlb21fcG9pbnRyYW5nZShhZXMoeT1lc3RpbWF0ZSwgeW1pbj0ubG93ZXIsIHltYXg9LnVwcGVyLCAKICAgICAgICAgICAgICAgICAgICAgIHg9ZmN0X3Jlb3JkZXIod2FyZDIsIGVzdGltYXRlKSwgY29sb3VyPW15X3BhbGV0dGUpKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgc2NhbGVfY29sb3VyX2lkZW50aXR5KG5hbWU9IiIpICsKICAgIHNjYWxlX3lfY29udGludW91cygpICsKICAgIHRoZW1lX2dnZGlzdCgpICsKICAgIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICAgIGxhYnMoeCA9ICIiLAogICAgICAgICB5ID0gIlJlbGF0aXZlIHJhdGUgKDk1JSBVSSkiKQp9CgoKCndhcmRfcGVha19pIDwtIHBsb3Rfd2FyZF9lZmZlY3QoZGF0YSA9IHdhcmRfZWZmZWN0cywgbWVhc3VyZSA9ICJSUi5wZWFrIikKd2FyZF9sZXZlbF9pIDwtIHBsb3Rfd2FyZF9lZmZlY3QoZGF0YSA9IHdhcmRfZWZmZWN0cywgbWVhc3VyZSA9ICJSUi5sZXZlbCIpCndhcmRfc2xvcGVfaSA8LSBwbG90X3dhcmRfZWZmZWN0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIuc2xvcGUiKQoKd2FyZF9wZWFrX2lpIDwtIHBsb3Rfd2FyZF9jYXQoZGF0YSA9IHdhcmRfZWZmZWN0cywgbWVhc3VyZSA9ICJSUi5wZWFrIikKd2FyZF9sZXZlbF9paSA8LSBwbG90X3dhcmRfY2F0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIubGV2ZWwiKQp3YXJkX3Nsb3BlX2lpIDwtIHBsb3Rfd2FyZF9jYXQoZGF0YSA9IHdhcmRfZWZmZWN0cywgbWVhc3VyZSA9ICJSUi5zbG9wZSIpCgpzNCA8LSAod2FyZF9wZWFrX2kgKyB3YXJkX2xldmVsX2kgKyB3YXJkX3Nsb3BlX2kpIC8KICAod2FyZF9wZWFrX2lpICsgd2FyZF9sZXZlbF9paSArIHdhcmRfc2xvcGVfaWkpCgpzNFtbMV1dIDwtIHM0W1sxXV0gKyBwbG90X2xheW91dCh0YWdfbGV2ZWwgPSAnbmV3JykKczRbWzJdXSA8LSBzNFtbMl1dICsgcGxvdF9sYXlvdXQodGFnX2xldmVsID0gJ25ldycpCnM0ICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSBjKCdBJywgJzEnKSkKCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMi5wbmciKSwgd2lkdGggPSAxNiwgaGVpZ2h0PTEwKQoKYGBgCgpDYWxjdWxhdGUgdGhlIGNvdW50ZXJmYWN0dWFsIHBlciB3YXJkCgpgYGB7cn0KCndhcmRfcHVsbW9uYXJ5X2NvdW50ZXJmIDwtIGNhbGN1bGF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEsIG1vZGVsPW1fcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBpbmdfdmFyID0gd2FyZCwgcmVfZm9ybXVsYT1+KDEgKyB5X251bSphY2ZfcGVyaW9kIHwgd2FyZCkpCgp3YXJkX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCk92ZXJhbGwgY291bnRlcmZhY3R1YWwgcGVyIHdhcmQKCmBgYHtyfQoKd2FyZF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgoKCiMjIyA4LiBFeHRyYS1wdWxtb25hcnkgVEIgbm90aWZpY2F0aW9ucwoKTm93IHdlIHdpbGwgbW9kZWwgdGhlIGV4dHJhLXB1bG1vbmFyeSBUQiBub3RpZmljYXRpb24gcmF0ZS4gU3RydWdnbGluZyBhIGJpdCB3aXRoIG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVsLCBzbyByZXZlcnQgdG8gUG9pc3Nvbi4KCiMjIyMgOC4xIEZpdCB0aGUgbW9kZWwKCmBgYHtyfQoKbV9leHRyYXB1bG1vbmFyeSA8LSBicm0oCiAgY2FzZXMgfiAxICsgeV9udW0qYWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YV9leHRyYXB1bG1vbmFyeSwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwKICAgICAgICAgICAgICAgICAgcHJpb3IgPSBwcmlvcihub3JtYWwoMCwxMDAwKSwgY2xhc3MgPSBJbnRlcmNlcHQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjAxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IoZXhwb25lbnRpYWwoMSksIGNsYXNzPXNkKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz1jb3IpKQoKc3VtbWFyeShtX2V4dHJhcHVsbW9uYXJ5KQpwbG90KG1fZXh0cmFwdWxtb25hcnkpCnBwX2NoZWNrKG1fZXh0cmFwdWxtb25hcnksIHR5cGU9J2VjZGZfb3ZlcmxheScpCgpgYGAKCiMjIyMgOC4yIFN1bW1hcnkgb2YgY2hhbmdlCgpTdW1tYXJpc2UgaW4gcGxvdAoKYGBge3J9CnBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQgJT4lIGZpbHRlcih5ZWFyPD0xOTYxKSwgbW9kZWw9bV9leHRyYXB1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIG91dGNvbWU9aW5jXzEwMGtfZXh0cmFwdWxtb25hcnksIHJlX2Zvcm11bGEgPSBOQSkKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczcucG5nIiksIHdpZHRoPTEwKQoKYGBgCgpTdW1tYXJpc2UgbnVtZXJpY2FsbHkuCgpgYGB7cn0KCm92ZXJhbGxfY2hhbmdlX2V4dHJhcHVsbW9uYXJ5IDwtIHN1bW1hcmlzZV9jaGFuZ2UobW9kZWxfZGF0YT1vdmVyYWxsX3NjYWZmb2xkLCBtb2RlbD1tX2V4dHJhcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yPXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3Zhcj1OVUxMLCByZV9mb3JtdWxhID0gTkEpCgojd2FudCB0byBrZWVwIHRoZSBzdW1tYXJ5IGVzdGltYXRlcyBoZXJlCnRva2VlcCA8LSBjKCJwZWFrX3N1bW1hcnkiLCAibGV2ZWxfc3VtbWFyeSIsICJzbG9wZV9zdW1tYXJ5IikKCiNzdW1tYXJ5IG1lYXN1cmVzIGluIGEgdGFibGUKb3ZlcmFsbF9jaGFuZ2VfZXh0cmFwdWxtb25hcnkgJT4lCiAga2VlcChuYW1lcyguKSAlaW4lIHRva2VlcCkgJT4lCiAgYmluZF9yb3dzKCkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGVzdGltYXRlOi51cHBlciksIG51bWJlciwgYWNjdXJhY3k9MC4wMSkpICU+JQogIHNlbGVjdChtZWFzdXJlLCBldmVyeXRoaW5nKCkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKCiMjIyMgOC4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpOdW1iZXJzIG9mIGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIG92ZXJhbGwuCgpgYGB7cn0KCm92ZXJhbGxfZXBfY291bnRlcmYgPC0gY2FsY3VsYXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YV9leHRyYXB1bG1vbmFyeSwgbW9kZWw9bV9leHRyYXB1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApCgpvdmVyYWxsX2VwX2NvdW50ZXJmJGNvdW50ZXJfcG9zdCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyLCBkaWZmX2luYzEwMGs6ZGlmZl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHJyX2luYzEwMGs6cnJfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpUb3RhbCBleHRyYXB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGJldHdlZW4gMTk1OCBhbmQgMTk2MwoKYGBge3J9CgpvdmVyYWxsX2VwX2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCk1ha2UgaW50byBUYWJsZSAyCgoKYGBge3J9CmJpbmRfcm93cygKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZShtb2RlbCA9ICJQVEJfd2FyZCIpLAoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUobW9kZWwgPSAiUFRCX292ZXJhbGwiKSwKCm92ZXJhbGxfZXBfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZShtb2RlbCA9ICJFUFRCIiksCgpvdmVyYWxsX2VwX2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKG1vZGVsID0gIkVQVEIgb3ZlcmFsbCIpCgopICU+JQogIHNlbGVjdChtb2RlbCwgeWVhciwgZGlmZl9pbmMxMDBrLCBkaWZmX2luYzEwMGsubG93ZXI6cnJfaW5jMTAway51cHBlciwgCiAgICAgICAgIGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwKICAgICAgICAgcGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSAlPiUKICB0cmFuc211dGUobW9kZWw9bW9kZWwsIHllYXI9eWVhciwKICAgICAgICAgICAgZGlmZl9jbnIgPSBnbHVlKCJ7ZGlmZl9pbmMxMDBrfSAoe2RpZmZfaW5jMTAway5sb3dlcn0gdG8ge2RpZmZfaW5jMTAway51cHBlcn0pIiksCiAgICAgICAgICAgIHJyID0gZ2x1ZSgie3JyX2luYzEwMGt9ICh7cnJfaW5jMTAway5sb3dlcn0gdG8ge3JyX2luYzEwMGsudXBwZXJ9KSIpLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9ICh7Y2FzZXNfYXZlcnRlZC5sb3dlcn0gdG8ge2Nhc2VzX2F2ZXJ0ZWQudXBwZXJ9KSIpLAogICAgICAgICAgICBwY3RfY2hhbmdlID0gZ2x1ZSgie3BjdF9jaGFuZ2V9ICh7cGN0X2NoYW5nZS5sb3dlcn0gdG8ge3BjdF9jaGFuZ2UudXBwZXJ9KSIpKSAlPiUKICB3cml0ZV9jc3YoaGVyZSgiZmlndXJlcy90YWJsZTIuY3N2IikpCgoKCmBgYAoKCgoKIyMjIyA4LjQgV2FyZC1sZXZlbCBleHRyYS1wdWxtb25hcnkgc3VtbWFyaWVzCgpXYXJkLWxldmVsIGV4dHJhLXB1bG1vbmFyeSBlc3RpbWF0ZXMgaW4gZ3JhcGhpY2FsIGZvcm0uCgpgYGB7cn0KCnBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhX2V4dHJhcHVsbW9uYXJ5LCBtb2RlbD1tX2V4dHJhcHVsbW9uYXJ5LCBvdXRjb21lID0gaW5jXzEwMGssIAogICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXIgPSB3YXJkLHJlX2Zvcm11bGEgPX4oeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpLCAKICAgICAgICAgICAgICAgICAgICB3YXJkKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zOC5wbmciKSwgd2lkdGg9MTAsIGhlaWdodD0xMikKCmBgYAoKTnVtZXJpY2FsIHN1bW1hcnkuCgpgYGB7cn0KCndhcmRfY2hhbmdlX2V4dHJhcHVsbW9uYXJ5IDwtIHN1bW1hcmlzZV9jaGFuZ2UobW9kZWxfZGF0YSA9IG1kYXRhX2V4dHJhcHVsbW9uYXJ5LCBtb2RlbCA9IG1fZXh0cmFwdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXI9d2FyZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gfih5X251bSphY2ZfcGVyaW9kIHwgd2FyZCkpIAoKI3dhbnQgdG8ga2VlcCB0aGUgc3VtbWFyeSBlc3RpbWF0ZXMgaGVyZQp0b2tlZXAgPC0gYygicGVha19zdW1tYXJ5IiwgImxldmVsX3N1bW1hcnkiLCAic2xvcGVfc3VtbWFyeSIpCgojc3VtbWFyeSBtZWFzdXJlcyBpbiBhIHRhYmxlCndhcmRfY2hhbmdlX2V4dHJhcHVsbW9uYXJ5ICAlPiUKICBrZWVwKG5hbWVzKC4pICVpbiUgdG9rZWVwKSAlPiUKICBiaW5kX3Jvd3MoKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoZXN0aW1hdGU6LnVwcGVyKSwgbnVtYmVyLCBhY2N1cmFjeT0wLjAxKSkgJT4lCiAgc2VsZWN0KG1lYXN1cmUsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgoKYGBgCgoKIyMjIDkuIEFnZS1zZXggbW9kZWwKCiMjIyMgOS4xIEZJdCB0aGUgbW9kZWwKCkZpdCB0aGUgbW9kZWwKCihOb3QgcmV3cml0dGVuIHRoZSBmdW5jdGlvbnMgZm9yIHRoaXMgeWV0KQoKYGBge3J9CgptZGF0YV9hZ2Vfc2V4IDwtIGNhc2VzX2J5X2FnZV9zZXggJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkgJT4lCiAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogIG11dGF0ZSh5X251bSA9IHJvd19udW1iZXIoKSkgJT4lCiAgdW5ncm91cCgpCgptX2FnZV9zZXggPC0gYnJtKAogIGNhc2VzIH4geV9udW0gKyAoYWNmX3BlcmlvZCkqKGFnZSpzZXgpICsgKGFjZl9wZXJpb2Q6eV9udW0pKihhZ2Uqc2V4KSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHByaW9yKG5vcm1hbCgwLDEpLCBjbGFzcyA9IEludGVyY2VwdCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGdhbW1hKDAuMDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpKQoKc3VtbWFyeShtX2FnZV9zZXgpCnBsb3QobV9hZ2Vfc2V4KQpwcF9jaGVjayhtX2FnZV9zZXgsIHR5cGU9J2VjZGZfb3ZlcmxheScpCgpgYGAKClN1bW1hcmlzZSBwb3N0ZXJpb3IKCgpgYGB7cn0KCiNwb3N0ZXJpb3IgZHJhd3MsIGFuZCBzdW1tYXJpc2UKYWdlX3NleF9zdW1tYXJ5IDwtIG1kYXRhX2FnZV9zZXggJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaSgpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpCgojY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQphZ2Vfc2V4X2NvdW50ZXJmYWN0IDwtIAogIHRpYmJsZSh5ZWFyID0gbWRhdGFfYWdlX3NleCR5ZWFyLAogICAgICAgICB5ZWFyMiA9IG1kYXRhX2FnZV9zZXgkeWVhcjIsCiAgICAgICAgIHlfbnVtID0gbWRhdGFfYWdlX3NleCR5X251bSwKICAgICAgICAgYWdlID0gbWRhdGFfYWdlX3NleCRhZ2UsCiAgICAgICAgIHNleCA9IG1kYXRhX2FnZV9zZXgkc2V4LAogICAgICAgICBhY2ZfcGVyaW9kID0gZmFjdG9yKCJhLiBwcmUtYWNmIikpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaSgpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0gIk0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0gIkYiIH4gIkZlbWFsZSIpKSAKCgoKYWdlX3NleF9zdW1tYXJ5ICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0gIk0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0gIkYiIH4gIkZlbWFsZSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkLmxvd2VyLCB5bWF4PS5lcHJlZC51cHBlciwgeD15ZWFyMiwgZ3JvdXAgPSBhY2ZfcGVyaW9kLCBmaWxsPWFjZl9wZXJpb2QpLCBhbHBoYT0wLjUpICsKICBnZW9tX3JpYmJvbihkYXRhID0gYWdlX3NleF9jb3VudGVyZmFjdCAlPiUgZmlsdGVyKHllYXI+PTE5NTYpLCAKICAgICAgICAgICAgICBhZXMoeW1pbj0uZXByZWQubG93ZXIsIHltYXg9LmVwcmVkLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICBnZW9tX2xpbmUoZGF0YSA9IGFnZV9zZXhfY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkLCB4PXllYXIyLCBjb2xvdXI9IkNvdW50ZXJmYWN0dWFsIikpICsKICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkLCB4PXllYXIyLCBncm91cD1hY2ZfcGVyaW9kLCAgY29sb3VyPWFjZl9wZXJpb2QpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJiLiBhY2YiIH4gIkNvdW50ZXJmYWN0dWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSksIAogIGFlcyh5PWNhc2VzLCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIGdnaDR4OjpmYWNldF9ncmlkMihhZ2V+c2V4LCBzY2FsZXMgPSAiZnJlZV95IiwgaW5kZXBlbmRlbnQgPSAieSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICBzY2FsZV9zaGFwZShuYW1lPSIiKSArCiAgbGFicygKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9ucyAobikiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zOS5wbmciKSwgaGVpZ2h0PTEwKQoKYGBgCgojIyMjIDkuMiBTdW1tYXJ5IG9mIGltcGFjdCBvZiBpbnRlcnZlbnRpb24KCkNhbGN1bGF0ZSBzdW1tYXJ5IGVmZmVjdHMKCmBgYHtyfQoKI1BlYWsKb3V0X2FnZV9zZXhfMSA8LSBjcm9zc2luZyhtZGF0YV9hZ2Vfc2V4ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDgpLAogICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYi4gYWNmIikpCgpwZWFrX2RyYXdzX2FnZV9zZXggPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXRfYWdlX3NleF8xLAogICAgICAgICAgICAgICAgICBvYmplY3QgPSBtX2FnZV9zZXgpICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsIGFnZSwgc2V4KSAlPiUKICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3QoLmVwcmVkKS9maXJzdCguZXByZWQpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnBlYWsiKQogIApwZWFrX3N1bW1hcnlfYWdlX3NleCA8LSBwZWFrX2RyYXdzX2FnZV9zZXggJT4lCiAgICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgICBtZWFuX3FpKGVzdGltYXRlKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnBlYWsiKQoKCiNMZXZlbAogCm91dF9hZ2Vfc2V4XzIgPC0gY3Jvc3NpbmcobWRhdGFfYWdlX3NleCAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeV9udW0sIGFnZSwgc2V4KSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSA9PSA5KSwKICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikpCiAgCmxldmVsX2RyYXdzX2FnZV9zZXggPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXRfYWdlX3NleF8yLAogICAgICAgICAgICAgICAgICBvYmplY3QgPSBtX2FnZV9zZXgpICU+JQogICAgYXJyYW5nZSh5X251bSwgLmRyYXcpICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsIGFnZSwgc2V4KSAlPiUKICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3QoLmVwcmVkKS9maXJzdCguZXByZWQpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLmxldmVsIikKICAKbGV2ZWxfc3VtbWFyeV9hZ2Vfc2V4IDwtIGxldmVsX2RyYXdzX2FnZV9zZXggJT4lCiAgICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgICBtZWFuX3FpKGVzdGltYXRlKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLmxldmVsIikKCiNTbG9wZQoKb3V0X2FnZV9zZXhfMyA8LSBjcm9zc2luZyhtZGF0YV9hZ2Vfc2V4ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtICVpbiUgYyg5LDE0KSksCiAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYy4gcG9zdC1hY2YiKSkKICAKc2xvcGVfZHJhd3NfYWdlX3NleCA8LSBhZGRfZXByZWRfZHJhd3MobmV3ZGF0YSA9IG91dF9hZ2Vfc2V4XzMsCiAgICAgICAgICAgICAgICAgIG9iamVjdCA9IG1fYWdlX3NleCkgJT4lCiAgICAgICAgYXJyYW5nZSh5X251bSkgJT4lCiAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgIGdyb3VwX2J5KC5kcmF3LCB5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgIHN1bW1hcmlzZShzbG9wZSA9IGxhc3QoLmVwcmVkKS9maXJzdCguZXByZWQpKSAlPiUKICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgZ3JvdXBfYnkoLmRyYXcsIGFnZSwgc2V4KSAlPiUKICAgICAgICBzdW1tYXJpc2UoZXN0aW1hdGUgPSBsYXN0KHNsb3BlKS9maXJzdChzbG9wZSkpICU+JQogICAgICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnNsb3BlIikKICAKc2xvcGVfc3VtbWFyeV9hZ2Vfc2V4IDwtIHNsb3BlX2RyYXdzX2FnZV9zZXggJT4lCiAgICAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogICAgICBtZWRpYW5fcWkoZXN0aW1hdGUpICU+JQogICAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5zbG9wZSIpCgpgYGAKCgpOdW1lcmljYWwgc3VtbWFyeSBvZiB0aGVzZSBzdW1tYXJ5IHJlc3VsdHMKCmBgYHtyfQoKYmluZF9yb3dzKAogIHBlYWtfc3VtbWFyeV9hZ2Vfc2V4LCBsZXZlbF9zdW1tYXJ5X2FnZV9zZXgsIHNsb3BlX3N1bW1hcnlfYWdlX3NleAopICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKCgpgYGAKCkFzIGEgZmlndXJlCgpgYGB7cn0KCnBlYWtfZ19hZ2Vfc2V4IDwtIHBlYWtfc3VtbWFyeV9hZ2Vfc2V4ICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0xKSwgbGluZXR5cGU9MikrCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4PWFnZSwgeT1lc3RpbWF0ZSwgeW1pbj0ubG93ZXIsIHltYXg9LnVwcGVyLCBncm91cD1zZXgsIGNvbG91cj1zZXgsIHNoYXBlPXNleCksCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjQ0Q3QUM1IiwgImNhZGV0Ymx1ZTMiKSwgbmFtZT0iIikgKwogIHNjYWxlX3NoYXBlKG5hbWU9IiIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSByYXRlICg5NSUgVUkpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKI2xldmVsIHBsb3QKbGV2ZWxfZ19hZ2Vfc2V4IDwtIGxldmVsX3N1bW1hcnlfYWdlX3NleCAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeD1hZ2UsIHk9ZXN0aW1hdGUsIHltaW49Lmxvd2VyLCB5bWF4PS51cHBlciwgZ3JvdXA9c2V4LCBjb2xvdXI9c2V4LCBzaGFwZT1zZXgpLAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0NEN0FDNSIsICJjYWRldGJsdWUzIiksIG5hbWU9IiIpICsKICBzY2FsZV9zaGFwZShuYW1lPSIiKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iUmVsYXRpdmUgcmF0ZSAoOTUlIFVJKSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCiNzbG9wZSBwbG90CnNsb3BlX2dfYWdlX3NleCA8LSBzbG9wZV9zdW1tYXJ5X2FnZV9zZXggJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTEpLCBsaW5ldHlwZT0yKSsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHg9YWdlLCB5PWVzdGltYXRlLCB5bWluPS5sb3dlciwgeW1heD0udXBwZXIsIGdyb3VwPXNleCwgY29sb3VyPXNleCwgc2hhcGU9c2V4KSwKICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSkpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNDRDdBQzUiLCAiY2FkZXRibHVlMyIpLCBuYW1lPSIiKSArCiAgc2NhbGVfc2hhcGUobmFtZT0iIikgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IlJlbGF0aXZlIHJhdGUgKDk1JSBVSSkiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKYGBgCgoKIyMjIyA5LjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKY291bnRlcmZhY3RfYWdlX3NleCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0gbV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhX2FnZV9zZXggJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFnZSwgc2V4KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFjZl9wZXJpb2QgPSAiYS4gcHJlLWFjZiIpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCBhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZF9jb3VudGVyZiA9IC5lcHJlZCkKICAKI0NhbGN1YXRlIHByZWRpY3RlZCBudW1iZXIgb2YgY2FzZXMgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgpwb3N0X2NoYW5nZV9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAKICAKI2ZvciB0aGUgb3ZlcmFsbCBwZXJpb2QKY291bnRlcmZhY3Rfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgc2VsZWN0KGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAgJT4lCiAgICAgIGdyb3VwX2J5KGFnZSwgc2V4LCAuZHJhdykgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWRfY291bnRlcmYgPSBzdW0oLmVwcmVkKSkgJT4lCiAgICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKQogIAojQ2FsY3VhdGUgaW5jaWRlbmNlIHBlciBkcmF3LCB0aGVuIHN1bW1hcmlzZS4KcG9zdF9jaGFuZ2Vfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdChhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCBhZ2UsIHNleCkgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWQgPSBzdW0oLmVwcmVkKSkgCiAgCmNvdW50ZXJfcG9zdF9vdmVyYWxsX2FnZV9zZXggPC0KICBsZWZ0X2pvaW4oY291bnRlcmZhY3Rfb3ZlcmFsbF9hZ2Vfc2V4LCBwb3N0X2NoYW5nZV9vdmVyYWxsX2FnZV9zZXgpICU+JQogICAgbXV0YXRlKGNhc2VzX2F2ZXJ0ZWQgPSAuZXByZWRfY291bnRlcmYtLmVwcmVkLAogICAgICAgICAgIHBjdF9jaGFuZ2UgPSAoLmVwcmVkIC0gLmVwcmVkX2NvdW50ZXJmKS8uZXByZWRfY291bnRlcmYpICU+JQogICAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKSAKCgphZ2Vfc2V4X3R4dCA8LSBjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgdHJhbnNtdXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIHNleCA9IHNleCwKICAgICAgICAgICAgYWdlID0gYWdlLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9XG4oe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfVxuKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIikpCgoKYWdlX3NleF90eHQgJT4lIGRhdGF0YWJsZSgpCgoKYGBgCgpgYGB7cn0KCmNvdW50ZXJmYWN0dWFsX2dfYWdlX3NleCA8LSBjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4ICU+JSAKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeCA9IGFnZSwgeT1jYXNlc19hdmVydGVkLCB5bWluPWNhc2VzX2F2ZXJ0ZWQubG93ZXIsIHltYXg9Y2FzZXNfYXZlcnRlZC51cHBlciwgY29sb3VyPXNleCwgc2hhcGU9c2V4KSwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC41KSkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNDRDdBQzUiLCAiY2FkZXRibHVlMyIpLCBuYW1lPSIiKSArCiAgc2NhbGVfc2hhcGUobmFtZT0iIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9Ik51bWJlciAoOTUlIFVJKSIsCiAgICAgICBjb2xvdXI9IiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmNvdW50ZXJmYWN0dWFsX2dfYWdlX3NleApgYGAKCkpvaW4gdG9nZXRoZXIgZm9yIEZpZ3VyZSAzLgoKCmBgYHtyfQoKKHBlYWtfZ19hZ2Vfc2V4ICsgbGV2ZWxfZ19hZ2Vfc2V4KSAvIChzbG9wZV9nX2FnZV9zZXggKyBjb3VudGVyZmFjdHVhbF9nX2FnZV9zZXgpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKSAmIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvZjMucG5nIiksIHdpZHRoID0gMTIsIGhlaWdodD04KQoKCmBgYAo=